Gravity PDF - Version 1.0.0

Version Description

Download this release

Release Info

Developer Blue Liquid Designs
Plugin Icon 128x128 Gravity PDF
Version 1.0.0
Comparing to
See all releases

Version 1.0.0

Files changed (88) hide show
  1. README.txt +61 -0
  2. dompdf/LICENSE.LGPL +456 -0
  3. dompdf/_notes/dwsync.xml +21 -0
  4. dompdf/changelog.txt +213 -0
  5. dompdf/docblox.dist.xml +20 -0
  6. dompdf/dompdf.php +286 -0
  7. dompdf/dompdf_config.custom.inc.php +29 -0
  8. dompdf/dompdf_config.inc.php +384 -0
  9. dompdf/include/_notes/dwsync.xml +143 -0
  10. dompdf/include/absolute_positioner.cls.php +125 -0
  11. dompdf/include/abstract_renderer.cls.php +865 -0
  12. dompdf/include/attribute_translator.cls.php +477 -0
  13. dompdf/include/autoload.inc.php +86 -0
  14. dompdf/include/block_frame_decorator.cls.php +265 -0
  15. dompdf/include/block_frame_reflower.cls.php +776 -0
  16. dompdf/include/block_positioner.cls.php +54 -0
  17. dompdf/include/block_renderer.cls.php +190 -0
  18. dompdf/include/cached_pdf_decorator.cls.php +154 -0
  19. dompdf/include/canvas.cls.php +324 -0
  20. dompdf/include/canvas_factory.cls.php +59 -0
  21. dompdf/include/cellmap.cls.php +728 -0
  22. dompdf/include/cpdf_adapter.cls.php +850 -0
  23. dompdf/include/css_color.cls.php +257 -0
  24. dompdf/include/dompdf.cls.php +935 -0
  25. dompdf/include/dompdf_exception.cls.php +27 -0
  26. dompdf/include/dompdf_image_exception.cls.php +27 -0
  27. dompdf/include/file.skel +9 -0
  28. dompdf/include/fixed_positioner.cls.php +87 -0
  29. dompdf/include/font_metrics.cls.php +335 -0
  30. dompdf/include/frame.cls.php +1113 -0
  31. dompdf/include/frame_decorator.cls.php +562 -0
  32. dompdf/include/frame_factory.cls.php +186 -0
  33. dompdf/include/frame_reflower.cls.php +415 -0
  34. dompdf/include/frame_tree.cls.php +224 -0
  35. dompdf/include/functions.inc.php +947 -0
  36. dompdf/include/gd_adapter.cls.php +811 -0
  37. dompdf/include/image_cache.cls.php +177 -0
  38. dompdf/include/image_frame_decorator.cls.php +80 -0
  39. dompdf/include/image_frame_reflower.cls.php +126 -0
  40. dompdf/include/image_renderer.cls.php +75 -0
  41. dompdf/include/inline_frame_decorator.cls.php +75 -0
  42. dompdf/include/inline_frame_reflower.cls.php +67 -0
  43. dompdf/include/inline_positioner.cls.php +71 -0
  44. dompdf/include/inline_renderer.cls.php +191 -0
  45. dompdf/include/javascript_embedder.cls.php +37 -0
  46. dompdf/include/line_box.cls.php +228 -0
  47. dompdf/include/list_bullet_frame_decorator.cls.php +66 -0
  48. dompdf/include/list_bullet_frame_reflower.cls.php +34 -0
  49. dompdf/include/list_bullet_image_frame_decorator.cls.php +143 -0
  50. dompdf/include/list_bullet_positioner.cls.php +74 -0
  51. dompdf/include/list_bullet_renderer.cls.php +219 -0
  52. dompdf/include/null_frame_decorator.cls.php +27 -0
  53. dompdf/include/null_frame_reflower.cls.php +22 -0
  54. dompdf/include/null_positioner.cls.php +24 -0
  55. dompdf/include/page_cache.cls.php +127 -0
  56. dompdf/include/page_frame_decorator.cls.php +596 -0
  57. dompdf/include/page_frame_reflower.cls.php +217 -0
  58. dompdf/include/pdflib_adapter.cls.php +1030 -0
  59. dompdf/include/php_evaluator.cls.php +48 -0
  60. dompdf/include/positioner.cls.php +52 -0
  61. dompdf/include/renderer.cls.php +286 -0
  62. dompdf/include/style.cls.php +2211 -0
  63. dompdf/include/stylesheet.cls.php +1362 -0
  64. dompdf/include/table_cell_frame_decorator.cls.php +103 -0
  65. dompdf/include/table_cell_frame_reflower.cls.php +115 -0
  66. dompdf/include/table_cell_positioner.cls.php +29 -0
  67. dompdf/include/table_cell_renderer.cls.php +156 -0
  68. dompdf/include/table_frame_decorator.cls.php +326 -0
  69. dompdf/include/table_frame_reflower.cls.php +567 -0
  70. dompdf/include/table_row_frame_decorator.cls.php +49 -0
  71. dompdf/include/table_row_frame_reflower.cls.php +62 -0
  72. dompdf/include/table_row_group_frame_decorator.cls.php +65 -0
  73. dompdf/include/table_row_group_frame_reflower.cls.php +60 -0
  74. dompdf/include/table_row_group_renderer.cls.php +41 -0
  75. dompdf/include/table_row_positioner.cls.php +36 -0
  76. dompdf/include/tcpdf_adapter.cls.php +466 -0
  77. dompdf/include/text_frame_decorator.cls.php +174 -0
  78. dompdf/include/text_frame_reflower.cls.php +433 -0
  79. dompdf/include/text_renderer.cls.php +150 -0
  80. dompdf/index.php +1 -0
  81. dompdf/lib/_notes/dwsync.xml +5 -0
  82. dompdf/lib/class.pdf.php +4969 -0
  83. dompdf/lib/fonts/Courier-Bold.afm +344 -0
  84. dompdf/lib/fonts/Courier-BoldOblique.afm +344 -0
  85. dompdf/lib/fonts/Courier-Oblique.afm +344 -0
  86. dompdf/lib/fonts/Courier.afm +344 -0
  87. dompdf/lib/fonts/DejaVuSans-Bold.ttf +0 -0
  88. dompdf/lib/fonts/DejaVuSans-Bold.ufm +2593 -0
README.txt ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: blueliquiddesigns
3
+ Donate link: http://www.blueliquiddesigns.com.au/index.php/gravity-forms-pdf-extended-plugin/
4
+ Tags: gravity, forms, pdf, automation, attachment
5
+ Requires at least: 3.4.1
6
+ Tested up to: 3.4.1
7
+ Stable tag: 1.0.0
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Gravity Forms PDF Extended allows you to save/view/download a PDF from the front- and back-end, and automate PDF creation on form submission.
12
+
13
+ == Description ==
14
+
15
+ Expanding on the good work of 'rposborne', who created the original [Gravity Forms PDF Plugin](http://wordpress.org/extend/plugins/gravity-forms-pdf/), the extended version overhauls the rendering process so developers have more control over the creation of PDFs.
16
+
17
+ **Features**
18
+
19
+ * Save PDF File on user submission of a Gravity Form so it can be attached to a notification
20
+ * Customise the PDF template without affecting the core Gravity Form Plugin
21
+ * Create multiple PDF templates
22
+ * View and download a PDF via the administrator interface
23
+ * Simple function to output PDF via template / plugin
24
+
25
+ **Tutorial**
26
+ [Head to Blue Liquid Designs](http://www.blueliquiddesigns.com.au/index.php/gravity-forms-pdf-extended-plugin/) - the developer of the extended Gravity Forms PDF plugin - and view everything you need to know installing, configuring and using the plugin.
27
+
28
+ **Demo**
29
+ [See the Gravity Forms PDF Extended Plugin in action](http://www.blueliquiddesigns.com.au/index.php/gravity-forms-pdf-extended-plugin/#gf-demo).
30
+
31
+ == Installation ==
32
+
33
+ This section describes how to install the plugin and get it working.
34
+
35
+ 1. Upload this plugin to your website and activate it
36
+ 2. Modify the PDF template file, *pdf-print-entry.php*, inside the gravity-forms-pdf-extended plugin folder to suit your requirements.
37
+ 3. To create a PDF on form submission and add as an email attachment read the tutorial: [http://blueliquiddesigns.com.au/gravity-forms-pdf-extended-plugin/](http://blueliquiddesigns.com.au/index.php/gravity-forms-pdf-extended-plugin/)
38
+
39
+ == Frequently Asked Questions ==
40
+
41
+ = I get the error message: Fatal error: Call to undefined method DOMText::getAttribute() on line ###. =
42
+ This is generally caused by invalid HTML. [Read the plugin documentation](http://www.blueliquiddesigns.com.au/index.php/gravity-forms-pdf-extended-plugin/#gf-the-template) for an easy method to debug the issue.
43
+
44
+ = I added an image to the template file and got the error 'Image not readable or empty'. =
45
+ Make sure you use an absolute path to the file e.g. http://www.your-site.com/my-image.jpg. Also, check that the 'temp' folder in *../gravity-forms-pdf-extended/dompdf/* is writable by your web server.
46
+
47
+ = I want to have multiple PDF template files. =
48
+ Copy the *pdf-print-entry.php* file (located in the plugin directory) and pass the new template name to the PDF_Generator() function inside the gform_pdf_create() function.
49
+
50
+ = I want users to be able to download the PDF from the server. =
51
+ By deleting the .htaccess file in the 'output' folder you'll be able to access the PDFs through a web browser. Use the get_pdf_filename() function to get the PDF's name.
52
+
53
+ == Screenshots ==
54
+
55
+ 1. View a PDF from the Form List
56
+ 2. View or download the PDF from a form entry.
57
+
58
+ == Changelog ==
59
+
60
+ = 1.0.0 =
61
+ * First release.
dompdf/LICENSE.LGPL ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 2.1, February 1999
3
+
4
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ [This is the first released version of the Lesser GPL. It also counts
10
+ as the successor of the GNU Library Public License, version 2, hence
11
+ the version number 2.1.]
12
+
13
+ Preamble
14
+
15
+ The licenses for most software are designed to take away your
16
+ freedom to share and change it. By contrast, the GNU General Public
17
+ Licenses are intended to guarantee your freedom to share and change
18
+ free software--to make sure the software is free for all its users.
19
+
20
+ This license, the Lesser General Public License, applies to some
21
+ specially designated software packages--typically libraries--of the
22
+ Free Software Foundation and other authors who decide to use it. You
23
+ can use it too, but we suggest you first think carefully about whether
24
+ this license or the ordinary General Public License is the better
25
+ strategy to use in any particular case, based on the explanations below.
26
+
27
+ When we speak of free software, we are referring to freedom of use,
28
+ not price. Our General Public Licenses are designed to make sure that
29
+ you have the freedom to distribute copies of free software (and charge
30
+ for this service if you wish); that you receive source code or can get
31
+ it if you want it; that you can change the software and use pieces of
32
+ it in new free programs; and that you are informed that you can do
33
+ these things.
34
+
35
+ To protect your rights, we need to make restrictions that forbid
36
+ distributors to deny you these rights or to ask you to surrender these
37
+ rights. These restrictions translate to certain responsibilities for
38
+ you if you distribute copies of the library or if you modify it.
39
+
40
+ For example, if you distribute copies of the library, whether gratis
41
+ or for a fee, you must give the recipients all the rights that we gave
42
+ you. You must make sure that they, too, receive or can get the source
43
+ code. If you link other code with the library, you must provide
44
+ complete object files to the recipients, so that they can relink them
45
+ with the library after making changes to the library and recompiling
46
+ it. And you must show them these terms so they know their rights.
47
+
48
+ We protect your rights with a two-step method: (1) we copyright the
49
+ library, and (2) we offer you this license, which gives you legal
50
+ permission to copy, distribute and/or modify the library.
51
+
52
+ To protect each distributor, we want to make it very clear that
53
+ there is no warranty for the free library. Also, if the library is
54
+ modified by someone else and passed on, the recipients should know
55
+ that what they have is not the original version, so that the original
56
+ author's reputation will not be affected by problems that might be
57
+ introduced by others.
58
+
59
+ Finally, software patents pose a constant threat to the existence of
60
+ any free program. We wish to make sure that a company cannot
61
+ effectively restrict the users of a free program by obtaining a
62
+ restrictive license from a patent holder. Therefore, we insist that
63
+ any patent license obtained for a version of the library must be
64
+ consistent with the full freedom of use specified in this license.
65
+
66
+ Most GNU software, including some libraries, is covered by the
67
+ ordinary GNU General Public License. This license, the GNU Lesser
68
+ General Public License, applies to certain designated libraries, and
69
+ is quite different from the ordinary General Public License. We use
70
+ this license for certain libraries in order to permit linking those
71
+ libraries into non-free programs.
72
+
73
+ When a program is linked with a library, whether statically or using
74
+ a shared library, the combination of the two is legally speaking a
75
+ combined work, a derivative of the original library. The ordinary
76
+ General Public License therefore permits such linking only if the
77
+ entire combination fits its criteria of freedom. The Lesser General
78
+ Public License permits more lax criteria for linking other code with
79
+ the library.
80
+
81
+ We call this license the "Lesser" General Public License because it
82
+ does Less to protect the user's freedom than the ordinary General
83
+ Public License. It also provides other free software developers Less
84
+ of an advantage over competing non-free programs. These disadvantages
85
+ are the reason we use the ordinary General Public License for many
86
+ libraries. However, the Lesser license provides advantages in certain
87
+ special circumstances.
88
+
89
+ For example, on rare occasions, there may be a special need to
90
+ encourage the widest possible use of a certain library, so that it becomes
91
+ a de-facto standard. To achieve this, non-free programs must be
92
+ allowed to use the library. A more frequent case is that a free
93
+ library does the same job as widely used non-free libraries. In this
94
+ case, there is little to gain by limiting the free library to free
95
+ software only, so we use the Lesser General Public License.
96
+
97
+ In other cases, permission to use a particular library in non-free
98
+ programs enables a greater number of people to use a large body of
99
+ free software. For example, permission to use the GNU C Library in
100
+ non-free programs enables many more people to use the whole GNU
101
+ operating system, as well as its variant, the GNU/Linux operating
102
+ system.
103
+
104
+ Although the Lesser General Public License is Less protective of the
105
+ users' freedom, it does ensure that the user of a program that is
106
+ linked with the Library has the freedom and the wherewithal to run
107
+ that program using a modified version of the Library.
108
+
109
+ The precise terms and conditions for copying, distribution and
110
+ modification follow. Pay close attention to the difference between a
111
+ "work based on the library" and a "work that uses the library". The
112
+ former contains code derived from the library, whereas the latter must
113
+ be combined with the library in order to run.
114
+
115
+ GNU LESSER GENERAL PUBLIC LICENSE
116
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
+
118
+ 0. This License Agreement applies to any software library or other
119
+ program which contains a notice placed by the copyright holder or
120
+ other authorized party saying it may be distributed under the terms of
121
+ this Lesser General Public License (also called "this License").
122
+ Each licensee is addressed as "you".
123
+
124
+ A "library" means a collection of software functions and/or data
125
+ prepared so as to be conveniently linked with application programs
126
+ (which use some of those functions and data) to form executables.
127
+
128
+ The "Library", below, refers to any such software library or work
129
+ which has been distributed under these terms. A "work based on the
130
+ Library" means either the Library or any derivative work under
131
+ copyright law: that is to say, a work containing the Library or a
132
+ portion of it, either verbatim or with modifications and/or translated
133
+ straightforwardly into another language. (Hereinafter, translation is
134
+ included without limitation in the term "modification".)
135
+
136
+ "Source code" for a work means the preferred form of the work for
137
+ making modifications to it. For a library, complete source code means
138
+ all the source code for all modules it contains, plus any associated
139
+ interface definition files, plus the scripts used to control compilation
140
+ and installation of the library.
141
+
142
+ Activities other than copying, distribution and modification are not
143
+ covered by this License; they are outside its scope. The act of
144
+ running a program using the Library is not restricted, and output from
145
+ such a program is covered only if its contents constitute a work based
146
+ on the Library (independent of the use of the Library in a tool for
147
+ writing it). Whether that is true depends on what the Library does
148
+ and what the program that uses the Library does.
149
+
150
+ 1. You may copy and distribute verbatim copies of the Library's
151
+ complete source code as you receive it, in any medium, provided that
152
+ you conspicuously and appropriately publish on each copy an
153
+ appropriate copyright notice and disclaimer of warranty; keep intact
154
+ all the notices that refer to this License and to the absence of any
155
+ warranty; and distribute a copy of this License along with the
156
+ Library.
157
+
158
+ You may charge a fee for the physical act of transferring a copy,
159
+ and you may at your option offer warranty protection in exchange for a
160
+ fee.
161
+
162
+ 2. You may modify your copy or copies of the Library or any portion
163
+ of it, thus forming a work based on the Library, and copy and
164
+ distribute such modifications or work under the terms of Section 1
165
+ above, provided that you also meet all of these conditions:
166
+
167
+ a) The modified work must itself be a software library.
168
+
169
+ b) You must cause the files modified to carry prominent notices
170
+ stating that you changed the files and the date of any change.
171
+
172
+ c) You must cause the whole of the work to be licensed at no
173
+ charge to all third parties under the terms of this License.
174
+
175
+ d) If a facility in the modified Library refers to a function or a
176
+ table of data to be supplied by an application program that uses
177
+ the facility, other than as an argument passed when the facility
178
+ is invoked, then you must make a good faith effort to ensure that,
179
+ in the event an application does not supply such function or
180
+ table, the facility still operates, and performs whatever part of
181
+ its purpose remains meaningful.
182
+
183
+ (For example, a function in a library to compute square roots has
184
+ a purpose that is entirely well-defined independent of the
185
+ application. Therefore, Subsection 2d requires that any
186
+ application-supplied function or table used by this function must
187
+ be optional: if the application does not supply it, the square
188
+ root function must still compute square roots.)
189
+
190
+ These requirements apply to the modified work as a whole. If
191
+ identifiable sections of that work are not derived from the Library,
192
+ and can be reasonably considered independent and separate works in
193
+ themselves, then this License, and its terms, do not apply to those
194
+ sections when you distribute them as separate works. But when you
195
+ distribute the same sections as part of a whole which is a work based
196
+ on the Library, the distribution of the whole must be on the terms of
197
+ this License, whose permissions for other licensees extend to the
198
+ entire whole, and thus to each and every part regardless of who wrote
199
+ it.
200
+
201
+ Thus, it is not the intent of this section to claim rights or contest
202
+ your rights to work written entirely by you; rather, the intent is to
203
+ exercise the right to control the distribution of derivative or
204
+ collective works based on the Library.
205
+
206
+ In addition, mere aggregation of another work not based on the Library
207
+ with the Library (or with a work based on the Library) on a volume of
208
+ a storage or distribution medium does not bring the other work under
209
+ the scope of this License.
210
+
211
+ 3. You may opt to apply the terms of the ordinary GNU General Public
212
+ License instead of this License to a given copy of the Library. To do
213
+ this, you must alter all the notices that refer to this License, so
214
+ that they refer to the ordinary GNU General Public License, version 2,
215
+ instead of to this License. (If a newer version than version 2 of the
216
+ ordinary GNU General Public License has appeared, then you can specify
217
+ that version instead if you wish.) Do not make any other change in
218
+ these notices.
219
+
220
+ Once this change is made in a given copy, it is irreversible for
221
+ that copy, so the ordinary GNU General Public License applies to all
222
+ subsequent copies and derivative works made from that copy.
223
+
224
+ This option is useful when you wish to copy part of the code of
225
+ the Library into a program that is not a library.
226
+
227
+ 4. You may copy and distribute the Library (or a portion or
228
+ derivative of it, under Section 2) in object code or executable form
229
+ under the terms of Sections 1 and 2 above provided that you accompany
230
+ it with the complete corresponding machine-readable source code, which
231
+ must be distributed under the terms of Sections 1 and 2 above on a
232
+ medium customarily used for software interchange.
233
+
234
+ If distribution of object code is made by offering access to copy
235
+ from a designated place, then offering equivalent access to copy the
236
+ source code from the same place satisfies the requirement to
237
+ distribute the source code, even though third parties are not
238
+ compelled to copy the source along with the object code.
239
+
240
+ 5. A program that contains no derivative of any portion of the
241
+ Library, but is designed to work with the Library by being compiled or
242
+ linked with it, is called a "work that uses the Library". Such a
243
+ work, in isolation, is not a derivative work of the Library, and
244
+ therefore falls outside the scope of this License.
245
+
246
+ However, linking a "work that uses the Library" with the Library
247
+ creates an executable that is a derivative of the Library (because it
248
+ contains portions of the Library), rather than a "work that uses the
249
+ library". The executable is therefore covered by this License.
250
+ Section 6 states terms for distribution of such executables.
251
+
252
+ When a "work that uses the Library" uses material from a header file
253
+ that is part of the Library, the object code for the work may be a
254
+ derivative work of the Library even though the source code is not.
255
+ Whether this is true is especially significant if the work can be
256
+ linked without the Library, or if the work is itself a library. The
257
+ threshold for this to be true is not precisely defined by law.
258
+
259
+ If such an object file uses only numerical parameters, data
260
+ structure layouts and accessors, and small macros and small inline
261
+ functions (ten lines or less in length), then the use of the object
262
+ file is unrestricted, regardless of whether it is legally a derivative
263
+ work. (Executables containing this object code plus portions of the
264
+ Library will still fall under Section 6.)
265
+
266
+ Otherwise, if the work is a derivative of the Library, you may
267
+ distribute the object code for the work under the terms of Section 6.
268
+ Any executables containing that work also fall under Section 6,
269
+ whether or not they are linked directly with the Library itself.
270
+
271
+ 6. As an exception to the Sections above, you may also combine or
272
+ link a "work that uses the Library" with the Library to produce a
273
+ work containing portions of the Library, and distribute that work
274
+ under terms of your choice, provided that the terms permit
275
+ modification of the work for the customer's own use and reverse
276
+ engineering for debugging such modifications.
277
+
278
+ You must give prominent notice with each copy of the work that the
279
+ Library is used in it and that the Library and its use are covered by
280
+ this License. You must supply a copy of this License. If the work
281
+ during execution displays copyright notices, you must include the
282
+ copyright notice for the Library among them, as well as a reference
283
+ directing the user to the copy of this License. Also, you must do one
284
+ of these things:
285
+
286
+ a) Accompany the work with the complete corresponding
287
+ machine-readable source code for the Library including whatever
288
+ changes were used in the work (which must be distributed under
289
+ Sections 1 and 2 above); and, if the work is an executable linked
290
+ with the Library, with the complete machine-readable "work that
291
+ uses the Library", as object code and/or source code, so that the
292
+ user can modify the Library and then relink to produce a modified
293
+ executable containing the modified Library. (It is understood
294
+ that the user who changes the contents of definitions files in the
295
+ Library will not necessarily be able to recompile the application
296
+ to use the modified definitions.)
297
+
298
+ b) Use a suitable shared library mechanism for linking with the
299
+ Library. A suitable mechanism is one that (1) uses at run time a
300
+ copy of the library already present on the user's computer system,
301
+ rather than copying library functions into the executable, and (2)
302
+ will operate properly with a modified version of the library, if
303
+ the user installs one, as long as the modified version is
304
+ interface-compatible with the version that the work was made with.
305
+
306
+ c) Accompany the work with a written offer, valid for at
307
+ least three years, to give the same user the materials
308
+ specified in Subsection 6a, above, for a charge no more
309
+ than the cost of performing this distribution.
310
+
311
+ d) If distribution of the work is made by offering access to copy
312
+ from a designated place, offer equivalent access to copy the above
313
+ specified materials from the same place.
314
+
315
+ e) Verify that the user has already received a copy of these
316
+ materials or that you have already sent this user a copy.
317
+
318
+ For an executable, the required form of the "work that uses the
319
+ Library" must include any data and utility programs needed for
320
+ reproducing the executable from it. However, as a special exception,
321
+ the materials to be distributed need not include anything that is
322
+ normally distributed (in either source or binary form) with the major
323
+ components (compiler, kernel, and so on) of the operating system on
324
+ which the executable runs, unless that component itself accompanies
325
+ the executable.
326
+
327
+ It may happen that this requirement contradicts the license
328
+ restrictions of other proprietary libraries that do not normally
329
+ accompany the operating system. Such a contradiction means you cannot
330
+ use both them and the Library together in an executable that you
331
+ distribute.
332
+
333
+ 7. You may place library facilities that are a work based on the
334
+ Library side-by-side in a single library together with other library
335
+ facilities not covered by this License, and distribute such a combined
336
+ library, provided that the separate distribution of the work based on
337
+ the Library and of the other library facilities is otherwise
338
+ permitted, and provided that you do these two things:
339
+
340
+ a) Accompany the combined library with a copy of the same work
341
+ based on the Library, uncombined with any other library
342
+ facilities. This must be distributed under the terms of the
343
+ Sections above.
344
+
345
+ b) Give prominent notice with the combined library of the fact
346
+ that part of it is a work based on the Library, and explaining
347
+ where to find the accompanying uncombined form of the same work.
348
+
349
+ 8. You may not copy, modify, sublicense, link with, or distribute
350
+ the Library except as expressly provided under this License. Any
351
+ attempt otherwise to copy, modify, sublicense, link with, or
352
+ distribute the Library is void, and will automatically terminate your
353
+ rights under this License. However, parties who have received copies,
354
+ or rights, from you under this License will not have their licenses
355
+ terminated so long as such parties remain in full compliance.
356
+
357
+ 9. You are not required to accept this License, since you have not
358
+ signed it. However, nothing else grants you permission to modify or
359
+ distribute the Library or its derivative works. These actions are
360
+ prohibited by law if you do not accept this License. Therefore, by
361
+ modifying or distributing the Library (or any work based on the
362
+ Library), you indicate your acceptance of this License to do so, and
363
+ all its terms and conditions for copying, distributing or modifying
364
+ the Library or works based on it.
365
+
366
+ 10. Each time you redistribute the Library (or any work based on the
367
+ Library), the recipient automatically receives a license from the
368
+ original licensor to copy, distribute, link with or modify the Library
369
+ subject to these terms and conditions. You may not impose any further
370
+ restrictions on the recipients' exercise of the rights granted herein.
371
+ You are not responsible for enforcing compliance by third parties with
372
+ this License.
373
+
374
+ 11. If, as a consequence of a court judgment or allegation of patent
375
+ infringement or for any other reason (not limited to patent issues),
376
+ conditions are imposed on you (whether by court order, agreement or
377
+ otherwise) that contradict the conditions of this License, they do not
378
+ excuse you from the conditions of this License. If you cannot
379
+ distribute so as to satisfy simultaneously your obligations under this
380
+ License and any other pertinent obligations, then as a consequence you
381
+ may not distribute the Library at all. For example, if a patent
382
+ license would not permit royalty-free redistribution of the Library by
383
+ all those who receive copies directly or indirectly through you, then
384
+ the only way you could satisfy both it and this License would be to
385
+ refrain entirely from distribution of the Library.
386
+
387
+ If any portion of this section is held invalid or unenforceable under any
388
+ particular circumstance, the balance of the section is intended to apply,
389
+ and the section as a whole is intended to apply in other circumstances.
390
+
391
+ It is not the purpose of this section to induce you to infringe any
392
+ patents or other property right claims or to contest validity of any
393
+ such claims; this section has the sole purpose of protecting the
394
+ integrity of the free software distribution system which is
395
+ implemented by public license practices. Many people have made
396
+ generous contributions to the wide range of software distributed
397
+ through that system in reliance on consistent application of that
398
+ system; it is up to the author/donor to decide if he or she is willing
399
+ to distribute software through any other system and a licensee cannot
400
+ impose that choice.
401
+
402
+ This section is intended to make thoroughly clear what is believed to
403
+ be a consequence of the rest of this License.
404
+
405
+ 12. If the distribution and/or use of the Library is restricted in
406
+ certain countries either by patents or by copyrighted interfaces, the
407
+ original copyright holder who places the Library under this License may add
408
+ an explicit geographical distribution limitation excluding those countries,
409
+ so that distribution is permitted only in or among countries not thus
410
+ excluded. In such case, this License incorporates the limitation as if
411
+ written in the body of this License.
412
+
413
+ 13. The Free Software Foundation may publish revised and/or new
414
+ versions of the Lesser General Public License from time to time.
415
+ Such new versions will be similar in spirit to the present version,
416
+ but may differ in detail to address new problems or concerns.
417
+
418
+ Each version is given a distinguishing version number. If the Library
419
+ specifies a version number of this License which applies to it and
420
+ "any later version", you have the option of following the terms and
421
+ conditions either of that version or of any later version published by
422
+ the Free Software Foundation. If the Library does not specify a
423
+ license version number, you may choose any version ever published by
424
+ the Free Software Foundation.
425
+
426
+ 14. If you wish to incorporate parts of the Library into other free
427
+ programs whose distribution conditions are incompatible with these,
428
+ write to the author to ask for permission. For software which is
429
+ copyrighted by the Free Software Foundation, write to the Free
430
+ Software Foundation; we sometimes make exceptions for this. Our
431
+ decision will be guided by the two goals of preserving the free status
432
+ of all derivatives of our free software and of promoting the sharing
433
+ and reuse of software generally.
434
+
435
+ NO WARRANTY
436
+
437
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438
+ WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440
+ OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444
+ LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445
+ THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
+
447
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449
+ AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456
+ DAMAGES.
dompdf/_notes/dwsync.xml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <dwsync>
3
+ <file name="LICENSE.LGPL" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
4
+ <file name="changelog.txt" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
5
+ <file name="docblox.dist.xml" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
6
+ <file name="dompdf.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
7
+ <file name="dompdf_config.custom.inc.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908550600000000" />
8
+ <file name="dompdf_config.inc.php" server="ftp.danielmarks.com.au" local="129908569017039464" remote="129908568600000000" />
9
+ <file name="index.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
10
+ <file name="load_font.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
11
+ <file name="readme.html" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
12
+ <file name="changelog.txt" server="216.235.107.57" local="129908529600000000" remote="129913284600000000" />
13
+ <file name="docblox.dist.xml" server="216.235.107.57" local="129908529600000000" remote="129913284600000000" />
14
+ <file name="dompdf.php" server="216.235.107.57" local="129908529600000000" remote="129913285200000000" />
15
+ <file name="dompdf_config.custom.inc.php" server="216.235.107.57" local="129914800781916146" remote="129914260800000000" />
16
+ <file name="dompdf_config.inc.php" server="216.235.107.57" local="129908569017039464" remote="129913285200000000" />
17
+ <file name="index.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
18
+ <file name="LICENSE.LGPL" server="216.235.107.57" local="129908529600000000" remote="129913312800000000" />
19
+ <file name="load_font.php" server="216.235.107.57" local="129908529600000000" remote="129913312800000000" />
20
+ <file name="readme.html" server="216.235.107.57" local="129908529600000000" remote="129913312800000000" />
21
+ </dwsync>
dompdf/changelog.txt ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ DOMPDF 0.6.0 beta 3 Release Notes
3
+
4
+
5
+ New Features
6
+
7
+
8
+ HTML/CSS/Images support
9
+
10
+ * Limited support for CSS float (disabled by default). See
11
+ DOMPDF_ENABLE_CSS_FLOAT
12
+ <http://code.google.com/p/dompdf/source/browse/tags/dompdf_0-6-0_beta3/dompdf/dompdf_config.inc.php#301>(r407,
13
+ r408, r415, r438, r457, r459, r471)
14
+ * Support for nth-child selectors (r407, r419)
15
+ * Support for @font-face (r407, r413)
16
+ * Font sub-setting now available (disabled by default). See
17
+ DOMPDF_ENABLE_FONTSUBSETTING
18
+ <http://code.google.com/p/dompdf/source/browse/tags/dompdf_0-6-0_beta3/dompdf/dompdf_config.inc.php#134>
19
+ (r466, r468, r469)
20
+ * Added an HTML5 Parser to enable improved document parsing/correction
21
+ (disabled by default). See DOMPDF_ENABLE_HTML5PARSER
22
+ <http://code.google.com/p/dompdf/source/browse/tags/dompdf_0-6-0_beta3/dompdf/dompdf_config.inc.php#316>
23
+ (r429, r430, r431, r441)
24
+ * Added support for ID in anchors tags (r373)
25
+ * Added a message for broken images and updated the broken_image.png
26
+ file to
27
+ something less aggressive (r377)
28
+ * Added support for transparent PNG in background-image and improved
29
+ background-image handling (r380, r404, r450, r453)
30
+ * Improved absolute positioning (r387, r409, r459, r460)
31
+ * Added support for the "rem" CSS unit (r389)
32
+ * Improved support for the "ex" CSS unit (r390)
33
+ * When parsing tables, TR elements not contained by TBODY, TFOOT, or
34
+ THEAD are automatically encapsulated by TBODY (r390)
35
+ * Added support for the CSS declaration word-wrap: break-word (r391)
36
+ * Added support for @page :left, :right, :first, :odd, and :even (r393)
37
+ * Added support for CSS visibility and empty-cells properties (r393)
38
+ * Type selectors (e.g. h1) are now case insensitive (r417)
39
+ * Image type detection is now based on file header instead of filename
40
+ extension (r422)
41
+ * Added support for HTML5-style charset metatag (<meta
42
+ charset=?utf-8?>) (r430)
43
+ * Added support for nested CSS counters (r438)
44
+ * Replaced TTF2UFM with php-font-lib and remove all dependencies on
45
+ TTF2UFM (r447)
46
+ * Table columns widths are now consistent across pages (r462)
47
+ * Added limited support for table captions (r456)
48
+ * Reduced rendering time by using caches (r469)
49
+
50
+
51
+ Installation / configuration / debugging
52
+
53
+ * Added frame (i.e. discreet document element) count to the sample
54
+ website debugger output (r399)
55
+ * DOMPDF_ENABLE_REMOTE is no longer needed for stylesheet references
56
+ that use a URL with domain component (r407)
57
+ * Added a ready-to-use web-based font installer to the sample website
58
+ (www/fonts.php) (r417, r418)
59
+ * Added the Unicode-compatible DejaVu Fonts <http://dejavu-fonts.org>
60
+ as part of the base installation (r388)
61
+
62
+
63
+ Major bug fixes
64
+
65
+ * Fixes compatibility with the Symfony framework autoloader (disabled
66
+ by default). See DOMPDF_AUTOLOAD_PREPEND
67
+ <http://code.google.com/p/dompdf/source/browse/tags/dompdf_0-6-0_beta3/dompdf/dompdf_config.inc.php#310>
68
+ (r374)
69
+ * Fixes errors in how margins were collapsed between siblings (r375)
70
+ * Improves the way lines are aligned vertically (see the
71
+ css_baseline example) (r375)
72
+ * Corrects the bounding box used for drawing backgrounds (r377)
73
+ * Fixes the z-index rendering process (r377, r378, r379, r393)
74
+ * Adds support for color styling inheritance (r390)
75
+ * Fixes bugs with nested tables and HTML attributes (r393)
76
+ * Fixes handling of URLs with non-ascii chars in the CPDF adapter (r394)
77
+ * Fixes a rgb()-style color parsing bug (r402)
78
+ * Fixes RLE4 compressed bitmap image support (r405)
79
+ * Fixes bug that caused generated content to occasionally display
80
+ multiple times (r406)
81
+ * Improves background image clipping (r417)
82
+ * Fixes table layout bug caused by zero-height rows (r464)
83
+ * Fixes layout bug caused by 100% width tables centered with margin
84
+ auto (r465)
85
+
86
+ For a full list of modifications since DOMPDF 0.6.0 beta 2 see the
87
+ changes listed on this page of the repository changelog
88
+ <http://code.google.com/p/dompdf/source/list?num=88&start=472&path=/trunk>.
89
+
90
+
91
+ Known Issues
92
+
93
+ * Table cells cannot be split over multiple pages
94
+ * CSS float support is not yet perfected
95
+
96
+ For a full list of known issues, see the issue tracker
97
+ <http://code.google.com/p/dompdf/issues/list>.
98
+
99
+
100
+ Installation Notes
101
+
102
+ * Starting with DOMPDF 0.6.0 the dompdf.php script will no longer
103
+ allow conversion of HTML document on the local file system that are
104
+ located outside of the path specified by DOMPDF_CHROOT
105
+ <http://code.google.com/p/dompdf/source/browse/tags/dompdf_0-6-0_beta3/dompdf/dompdf_config.inc.php#109>
106
+ * If you are installing DOMPDF on top of an existing installation you
107
+ should remove any existing font metrics. This can be done manually
108
+ or through the sample website (www/fonts.php).
109
+ * When upgrading to a new version of DOMPDF you must replace
110
+ dompdf_config.inc.php with the new one. To simplify the upgrade
111
+ process you can store your configuration settings in
112
+ dompdf_config.custom.inc.php (which does not need to be overwritten).
113
+
114
+ ------------------------------------------------------------------------
115
+
116
+
117
+ DOMPDF 0.6.0 beta 2
118
+
119
+
120
+ New Features
121
+
122
+
123
+ HTML/CSS/Images support
124
+
125
+ * CSS3: opacity, 2D transforms
126
+ * CSS2: outline, letter-spacing, z-index, position: relative,
127
+ overflow: hidden
128
+ * CSS Pseudo elements :before and :after with generated content
129
+ * CSS2 pseudo-selectors (last-child, disabled, checked, enabled)
130
+ * CSS3 attribute selectors (ends-width, starts-width, contains)
131
+ * Improves absolute positioning
132
+ * Adds fixed positioning
133
+ * CMYK colors and CMYK Jpeg images
134
+ * 32bit PNG with alpha channel (Cpdf backend)
135
+ * BMP images (8, 24 and 32 bit)
136
+ * Adds support for image embedding via ?data? URI
137
+ * Adds support for ordered list
138
+ * Adds support for embedding PDF JavaScript
139
+ * Uses the HTML document title element and certain meta tags to
140
+ populate the PDF?s meta information (title, author, keywords and
141
+ subject)
142
+ * Uses the ?alt? attribute of an image when the image is inaccessible
143
+ * Supports loading system fonts
144
+
145
+
146
+ Installation / configuration
147
+
148
+ * The demo page now shows the HTML file and the PDF document in an iframe
149
+ * Adds a setup/configuration tool that provides information about the
150
+ server configuration, dompdf parameters, and installed fonts.
151
+ * The font metrics cache files can now be cleared using the
152
+ setup/config tool
153
+ * Adds a debug tool that shows side-by-side the HTML file, the
154
+ rendered PDF, and a console showing memory consumption, rendering
155
+ time, warning, and debug messages
156
+ * Adds examples showing new features
157
+ * Moves ttf2ufm out of the DOMPDF code repository and into an external
158
+ project <http://code.google.com/p/ttf2ufm/>
159
+ * Disables inline PHP support by default
160
+ * Disables direct input in the examples page for non-localhost access
161
+ * Adds configuration option to help debugging (see DEBUG_LAYOUT) which
162
+ draws rectangles around the different types of blocks and frames
163
+
164
+
165
+ Major bug fixes
166
+
167
+ * Addresses memory leaks from running eval() on the font metrics cache
168
+ * Reduces memory consumption caused by the font metrics (when using
169
+ the Cpdf backend)
170
+ * Updates text wrapping to prevent splitting text into more lines than
171
+ needed (issue 198
172
+ <http://code.google.com/p/dompdf/issues/detail?id=198>)
173
+ * Implements a check against an infinite loop caused by table cells
174
+ larger than a page
175
+ * Improves text height and width calculations as well as placement
176
+ (improves, for example, justified text rendering for text that is
177
+ not iso-8859-1)
178
+ * Updates the fallback MBString functions
179
+ * Supports PHP 5.3 and includes improved compatibility with older
180
+ versions of PHP 5
181
+ * Improves image placement
182
+ * Addresses problems with table flow caused by empty table cells
183
+ * Addresses warning/errors caused by unrecognized CSS rules or selectors
184
+
185
+ For a full list of modifications since DOMPDF 0.6.0 beta 1 see the
186
+ repository changelog
187
+ <http://code.google.com/p/dompdf/source/list?path=/tags/dompdf_0-6-0_beta2&num=104>
188
+
189
+
190
+ Known Issues
191
+
192
+ * Table cells cannot be split over multiple pages
193
+ * Column widths of tables that span more than one page may not be
194
+ consistent across pages
195
+
196
+
197
+ Installation Notes
198
+
199
+ * Starting with dompdf 0.6.0 dompdf.php will no longer allow
200
+ conversion of HTML document on the local file system that are
201
+ located outside of the path specified by DOMPDF_CHROOT
202
+ * The format of the font metrics cache has changed as of this release.
203
+ You should manually remove any existing font metrics prior to
204
+ upgrading or use the setup/configuration tool to do so immediately
205
+ after.
206
+ * Inline PHP is *disabled* by default now (see DOMPDF_ENABLE_PHP)
207
+ * Because additional configuration options have been added you will
208
+ need to replace your dompdf_config.inc.php file with the new one.
209
+ You may modify this file or copy your configuration settings to
210
+ dompdf_config.custom.inc.php.
211
+
212
+
213
+
dompdf/docblox.dist.xml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <docblox>
3
+ <parser>
4
+ <target>docs</target>
5
+ </parser>
6
+ <transformer>
7
+ <target>docs</target>
8
+ </transformer>
9
+ <files>
10
+ <directory>.</directory>
11
+ <ignore>*/lib/fonts/*</ignore>
12
+ <ignore>*/lib/html5lib/*</ignore>
13
+ <ignore>*/lib/php-font-lib/*</ignore>
14
+ <ignore>*www/*</ignore>
15
+ <ignore>*.svn*</ignore>
16
+ </files>
17
+ <transformations>
18
+ <template name="new_black" />
19
+ </transformations>
20
+ </docblox>
dompdf/dompdf.php ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Command line utility to use dompdf.
4
+ * Can also be used with HTTP GET parameters
5
+ *
6
+ * @package dompdf
7
+ * @link http://www.dompdf.com/
8
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
9
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
10
+ * @version $Id: dompdf.php 448 2011-11-13 13:00:03Z fabien.menager $
11
+ */
12
+
13
+ /**
14
+ * Display command line usage
15
+ */
16
+ function dompdf_usage() {
17
+ $default_paper_size = DOMPDF_DEFAULT_PAPER_SIZE;
18
+
19
+ echo <<<EOD
20
+
21
+ Usage: {$_SERVER["argv"][0]} [options] html_file
22
+
23
+ html_file can be a filename, a url if fopen_wrappers are enabled, or the '-' character to read from standard input.
24
+
25
+ Options:
26
+ -h Show this message
27
+ -l List available paper sizes
28
+ -p size Paper size; something like 'letter', 'A4', 'legal', etc.
29
+ The default is '$default_paper_size'
30
+ -o orientation Either 'portrait' or 'landscape'. Default is 'portrait'
31
+ -b path Set the 'document root' of the html_file.
32
+ Relative urls (for stylesheets) are resolved using this directory.
33
+ Default is the directory of html_file.
34
+ -f file The output filename. Default is the input [html_file].pdf
35
+ -v Verbose: display html parsing warnings and file not found errors.
36
+ -d Very verbose: display oodles of debugging output: every frame
37
+ in the tree printed to stdout.
38
+ -t Comma separated list of debugging types (page-break,reflow,split)
39
+
40
+ EOD;
41
+ exit;
42
+ }
43
+
44
+ /**
45
+ * Parses command line options
46
+ *
47
+ * @return array The command line options
48
+ */
49
+ function getoptions() {
50
+
51
+ $opts = array();
52
+
53
+ if ( $_SERVER["argc"] == 1 )
54
+ return $opts;
55
+
56
+ $i = 1;
57
+ while ($i < $_SERVER["argc"]) {
58
+
59
+ switch ($_SERVER["argv"][$i]) {
60
+
61
+ case "--help":
62
+ case "-h":
63
+ $opts["h"] = true;
64
+ $i++;
65
+ break;
66
+
67
+ case "-l":
68
+ $opts["l"] = true;
69
+ $i++;
70
+ break;
71
+
72
+ case "-p":
73
+ if ( !isset($_SERVER["argv"][$i+1]) )
74
+ die("-p switch requires a size parameter\n");
75
+ $opts["p"] = $_SERVER["argv"][$i+1];
76
+ $i += 2;
77
+ break;
78
+
79
+ case "-o":
80
+ if ( !isset($_SERVER["argv"][$i+1]) )
81
+ die("-o switch requires an orientation parameter\n");
82
+ $opts["o"] = $_SERVER["argv"][$i+1];
83
+ $i += 2;
84
+ break;
85
+
86
+ case "-b":
87
+ if ( !isset($_SERVER["argv"][$i+1]) )
88
+ die("-b switch requires a path parameter\n");
89
+ $opts["b"] = $_SERVER["argv"][$i+1];
90
+ $i += 2;
91
+ break;
92
+
93
+ case "-f":
94
+ if ( !isset($_SERVER["argv"][$i+1]) )
95
+ die("-f switch requires a filename parameter\n");
96
+ $opts["f"] = $_SERVER["argv"][$i+1];
97
+ $i += 2;
98
+ break;
99
+
100
+ case "-v":
101
+ $opts["v"] = true;
102
+ $i++;
103
+ break;
104
+
105
+ case "-d":
106
+ $opts["d"] = true;
107
+ $i++;
108
+ break;
109
+
110
+ case "-t":
111
+ if ( !isset($_SERVER['argv'][$i + 1]) )
112
+ die("-t switch requires a comma separated list of types\n");
113
+ $opts["t"] = $_SERVER['argv'][$i+1];
114
+ $i += 2;
115
+ break;
116
+
117
+ default:
118
+ $opts["filename"] = $_SERVER["argv"][$i];
119
+ $i++;
120
+ break;
121
+ }
122
+
123
+ }
124
+ return $opts;
125
+ }
126
+
127
+ require_once("dompdf_config.inc.php");
128
+ global $_dompdf_show_warnings, $_dompdf_debug, $_DOMPDF_DEBUG_TYPES;
129
+
130
+ $sapi = php_sapi_name();
131
+ $options = array();
132
+
133
+ switch ( $sapi ) {
134
+
135
+ case "cli":
136
+
137
+ $opts = getoptions();
138
+
139
+ if ( isset($opts["h"]) || (!isset($opts["filename"]) && !isset($opts["l"])) ) {
140
+ dompdf_usage();
141
+ exit;
142
+ }
143
+
144
+ if ( isset($opts["l"]) ) {
145
+ echo "\nUnderstood paper sizes:\n";
146
+
147
+ foreach (array_keys(CPDF_Adapter::$PAPER_SIZES) as $size)
148
+ echo " " . mb_strtoupper($size) . "\n";
149
+ exit;
150
+ }
151
+ $file = $opts["filename"];
152
+
153
+ if ( isset($opts["p"]) )
154
+ $paper = $opts["p"];
155
+ else
156
+ $paper = DOMPDF_DEFAULT_PAPER_SIZE;
157
+
158
+ if ( isset($opts["o"]) )
159
+ $orientation = $opts["o"];
160
+ else
161
+ $orientation = "portrait";
162
+
163
+ if ( isset($opts["b"]) )
164
+ $base_path = $opts["b"];
165
+
166
+ if ( isset($opts["f"]) )
167
+ $outfile = $opts["f"];
168
+ else {
169
+ if ( $file === "-" )
170
+ $outfile = "dompdf_out.pdf";
171
+ else
172
+ $outfile = str_ireplace(array(".html", ".htm", ".php"), "", $file) . ".pdf";
173
+ }
174
+
175
+ if ( isset($opts["v"]) )
176
+ $_dompdf_show_warnings = true;
177
+
178
+ if ( isset($opts["d"]) ) {
179
+ $_dompdf_show_warnings = true;
180
+ $_dompdf_debug = true;
181
+ }
182
+
183
+ if ( isset($opts['t']) ) {
184
+ $arr = split(',',$opts['t']);
185
+ $types = array();
186
+ foreach ($arr as $type)
187
+ $types[ trim($type) ] = 1;
188
+ $_DOMPDF_DEBUG_TYPES = $types;
189
+ }
190
+
191
+ $save_file = true;
192
+
193
+ break;
194
+
195
+ default:
196
+
197
+ if ( isset($_GET["input_file"]) )
198
+ $file = rawurldecode($_GET["input_file"]);
199
+ else
200
+ throw new DOMPDF_Exception("An input file is required (i.e. input_file _GET variable).");
201
+
202
+ if ( isset($_GET["paper"]) )
203
+ $paper = rawurldecode($_GET["paper"]);
204
+ else
205
+ $paper = DOMPDF_DEFAULT_PAPER_SIZE;
206
+
207
+ if ( isset($_GET["orientation"]) )
208
+ $orientation = rawurldecode($_GET["orientation"]);
209
+ else
210
+ $orientation = "portrait";
211
+
212
+ if ( isset($_GET["base_path"]) ) {
213
+ $base_path = rawurldecode($_GET["base_path"]);
214
+ $file = $base_path . $file; # Set the input file
215
+ }
216
+
217
+ if ( isset($_GET["options"]) ) {
218
+ $options = $_GET["options"];
219
+ }
220
+
221
+ $file_parts = explode_url($file);
222
+
223
+ /* Check to see if the input file is local and, if so, that the base path falls within that specified by DOMDPF_CHROOT */
224
+ if(($file_parts['protocol'] == '' || $file_parts['protocol'] === 'file://')) {
225
+ $file = realpath($file);
226
+ if ( strpos($file, DOMPDF_CHROOT) !== 0 ) {
227
+ throw new DOMPDF_Exception("Permission denied on $file.");
228
+ }
229
+ }
230
+
231
+ $outfile = "dompdf_out.pdf"; # Don't allow them to set the output file
232
+ $save_file = false; # Don't save the file
233
+
234
+ break;
235
+ }
236
+
237
+ $dompdf = new DOMPDF();
238
+
239
+ if ( $file === "-" ) {
240
+ $str = "";
241
+ while ( !feof(STDIN) )
242
+ $str .= fread(STDIN, 4096);
243
+
244
+ $dompdf->load_html($str);
245
+
246
+ } else
247
+ $dompdf->load_html_file($file);
248
+
249
+ if ( isset($base_path) ) {
250
+ $dompdf->set_base_path($base_path);
251
+ }
252
+
253
+ $dompdf->set_paper($paper, $orientation);
254
+
255
+ $dompdf->render();
256
+
257
+ if ( $_dompdf_show_warnings ) {
258
+ global $_dompdf_warnings;
259
+ foreach ($_dompdf_warnings as $msg)
260
+ echo $msg . "\n";
261
+ echo $dompdf->get_canvas()->get_cpdf()->messages;
262
+ flush();
263
+ }
264
+
265
+ if ( $save_file ) {
266
+ // if ( !is_writable($outfile) )
267
+ // throw new DOMPDF_Exception("'$outfile' is not writable.");
268
+ if ( strtolower(DOMPDF_PDF_BACKEND) === "gd" )
269
+ $outfile = str_replace(".pdf", ".png", $outfile);
270
+
271
+ list($proto, $host, $path, $file) = explode_url($outfile);
272
+ if ( $proto != "" ) // i.e. not file://
273
+ $outfile = $file; // just save it locally, FIXME? could save it like wget: ./host/basepath/file
274
+
275
+ $outfile = realpath(dirname($outfile)) . DIRECTORY_SEPARATOR . basename($outfile);
276
+
277
+ if ( strpos($outfile, DOMPDF_CHROOT) !== 0 )
278
+ throw new DOMPDF_Exception("Permission denied.");
279
+
280
+ file_put_contents($outfile, $dompdf->output( array("compress" => 0) ));
281
+ exit(0);
282
+ }
283
+
284
+ if ( !headers_sent() ) {
285
+ $dompdf->stream($outfile, $options);
286
+ }
dompdf/dompdf_config.custom.inc.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //define("DOMPDF_TEMP_DIR", "/tmp");
3
+ //define("DOMPDF_CHROOT", DOMPDF_DIR);
4
+ //define("DOMPDF_UNICODE_ENABLED", false);
5
+ //define("DOMPDF_PDF_BACKEND", "PDFLib");
6
+ //define("DOMPDF_DEFAULT_MEDIA_TYPE", "print");
7
+ //define("DOMPDF_DEFAULT_PAPER_SIZE", "letter");
8
+ //define("DOMPDF_DEFAULT_FONT", "serif");
9
+ //define("DOMPDF_DPI", 72);
10
+ //define("DOMPDF_ENABLE_PHP", true);
11
+ //define("DOMPDF_ENABLE_REMOTE", true);
12
+ //define("DOMPDF_ENABLE_CSS_FLOAT", true);
13
+ //define("DOMPDF_ENABLE_JAVASCRIPT", false);
14
+ //define("DEBUGPNG", true);
15
+ //define("DEBUGKEEPTEMP", true);
16
+ //define("DEBUGCSS", true);
17
+ //define("DEBUG_LAYOUT", true);
18
+ //define("DEBUG_LAYOUT_LINES", false);
19
+ //define("DEBUG_LAYOUT_BLOCKS", false);
20
+ //define("DEBUG_LAYOUT_INLINE", false);
21
+ //define("DOMPDF_FONT_HEIGHT_RATIO", 1.0);
22
+ //define("DEBUG_LAYOUT_PADDINGBOX", false);
23
+ //define("DOMPDF_LOG_OUTPUT_FILE", DOMPDF_FONT_DIR."log.htm");
24
+ //define("DOMPDF_ENABLE_HTML5PARSER", true);
25
+ //define("DOMPDF_ENABLE_FONTSUBSETTING", true);
26
+
27
+ // DOMPDF authentication
28
+ //define("DOMPDF_ADMIN_USERNAME", "user");
29
+ //define("DOMPDF_ADMIN_PASSWORD", "password");
dompdf/dompdf_config.inc.php ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: dompdf_config.inc.php 468 2012-02-05 10:51:40Z fabien.menager $
10
+ */
11
+
12
+ //error_reporting(E_STRICT | E_ALL | E_DEPRECATED);
13
+ //ini_set("display_errors", 1);
14
+
15
+ PHP_VERSION >= 5.0 or die("DOMPDF requires PHP 5.0+");
16
+
17
+ /**
18
+ * The root of your DOMPDF installation
19
+ */
20
+ define("DOMPDF_DIR", str_replace(DIRECTORY_SEPARATOR, '/', realpath(dirname(__FILE__))));
21
+
22
+ /**
23
+ * The location of the DOMPDF include directory
24
+ */
25
+ define("DOMPDF_INC_DIR", DOMPDF_DIR . "/include");
26
+
27
+ /**
28
+ * The location of the DOMPDF lib directory
29
+ */
30
+ define("DOMPDF_LIB_DIR", DOMPDF_DIR . "/lib");
31
+
32
+ /**
33
+ * Some installations don't have $_SERVER['DOCUMENT_ROOT']
34
+ * http://fyneworks.blogspot.com/2007/08/php-documentroot-in-iis-windows-servers.html
35
+ */
36
+ if( !isset($_SERVER['DOCUMENT_ROOT']) ) {
37
+ $path = "";
38
+
39
+ if ( isset($_SERVER['SCRIPT_FILENAME']) )
40
+ $path = $_SERVER['SCRIPT_FILENAME'];
41
+ elseif ( isset($_SERVER['PATH_TRANSLATED']) )
42
+ $path = str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']);
43
+
44
+ $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($path, 0, 0-strlen($_SERVER['PHP_SELF'])));
45
+ }
46
+
47
+ /** Include the custom config file if it exists */
48
+ if ( file_exists(DOMPDF_DIR . "/dompdf_config.custom.inc.php") ){
49
+ require_once(DOMPDF_DIR . "/dompdf_config.custom.inc.php");
50
+ }
51
+
52
+ //FIXME: Some function definitions rely on the constants defined by DOMPDF. However, might this location prove problematic?
53
+ require_once(DOMPDF_INC_DIR . "/functions.inc.php");
54
+
55
+ /**
56
+ * Username and password used by the configuration utility in www/
57
+ */
58
+ def("DOMPDF_ADMIN_USERNAME", "user");
59
+ def("DOMPDF_ADMIN_PASSWORD", "password");
60
+
61
+ /**
62
+ * The location of the DOMPDF font directory
63
+ *
64
+ * If DOMPDF_FONT_DIR identical to DOMPDF_FONT_CACHE or user executing DOMPDF from the CLI,
65
+ * this directory must be writable by the webserver process ().
66
+ * *Please note the trailing slash.*
67
+ *
68
+ * Notes regarding fonts:
69
+ * Additional .afm font metrics can be added by executing load_font.php from command line.
70
+ *
71
+ * Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
72
+ * be embedded in the pdf file or the PDF may not display correctly. This can significantly
73
+ * increase file size and could violate copyright provisions of a font. Font subsetting is
74
+ * not currently supported.
75
+ *
76
+ * Any font specification in the source HTML is translated to the closest font available
77
+ * in the font directory.
78
+ *
79
+ * The pdf standard "Base 14 fonts" are:
80
+ * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
81
+ * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
82
+ * Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
83
+ * Symbol,
84
+ * ZapfDingbats,
85
+ *
86
+ * *Please note the trailing slash.*
87
+ */
88
+ def("DOMPDF_FONT_DIR", DOMPDF_DIR . "/lib/fonts/");
89
+
90
+ /**
91
+ * The location of the DOMPDF font cache directory
92
+ *
93
+ * Note this directory must be writable by the webserver process
94
+ * This folder must already exist!
95
+ * It contains the .afm files, on demand parsed, converted to php syntax and cached
96
+ * This folder can be the same as DOMPDF_FONT_DIR
97
+ */
98
+ def("DOMPDF_FONT_CACHE", DOMPDF_FONT_DIR);
99
+
100
+ /**
101
+ * The location of a temporary directory.
102
+ *
103
+ * The directory specified must be writeable by the webserver process.
104
+ * The temporary directory is required to download remote images and when
105
+ * using the PFDLib back end.
106
+ */
107
+ def("DOMPDF_TEMP_DIR", DOMPDF_DIR . "/temp/");
108
+
109
+ /**
110
+ * ==== IMPORTANT ====
111
+ *
112
+ * dompdf's "chroot": Prevents dompdf from accessing system files or other
113
+ * files on the webserver. All local files opened by dompdf must be in a
114
+ * subdirectory of this directory. DO NOT set it to '/' since this could
115
+ * allow an attacker to use dompdf to read any files on the server. This
116
+ * should be an absolute path.
117
+ * This is only checked on command line call by dompdf.php, but not by
118
+ * direct class use like:
119
+ * $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
120
+ */
121
+ def("DOMPDF_CHROOT", realpath(DOMPDF_DIR));
122
+
123
+ /**
124
+ * Whether to use Unicode fonts or not.
125
+ *
126
+ * When set to true the PDF backend must be set to "CPDF" and fonts must be
127
+ * loaded via load_font.php.
128
+ *
129
+ * When enabled, dompdf can support all Unicode glyphs. Any glyphs used in a
130
+ * document must be present in your fonts, however.
131
+ */
132
+ def("DOMPDF_UNICODE_ENABLED", true);
133
+
134
+ /**
135
+ * Whether to make font subsetting or not.
136
+ */
137
+ def("DOMPDF_ENABLE_FONTSUBSETTING", false);
138
+
139
+ /**
140
+ * The PDF rendering backend to use
141
+ *
142
+ * Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
143
+ * 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
144
+ * fall back on CPDF. 'GD' renders PDFs to graphic files. {@link
145
+ * Canvas_Factory} ultimately determines which rendering class to instantiate
146
+ * based on this setting.
147
+ *
148
+ * Both PDFLib & CPDF rendering backends provide sufficient rendering
149
+ * capabilities for dompdf, however additional features (e.g. object,
150
+ * image and font support, etc.) differ between backends. Please see
151
+ * {@link PDFLib_Adapter} for more information on the PDFLib backend
152
+ * and {@link CPDF_Adapter} and lib/class.pdf.php for more information
153
+ * on CPDF. Also see the documentation for each backend at the links
154
+ * below.
155
+ *
156
+ * The GD rendering backend is a little different than PDFLib and
157
+ * CPDF. Several features of CPDF and PDFLib are not supported or do
158
+ * not make any sense when creating image files. For example,
159
+ * multiple pages are not supported, nor are PDF 'objects'. Have a
160
+ * look at {@link GD_Adapter} for more information. GD support is new
161
+ * and experimental, so use it at your own risk.
162
+ *
163
+ * @link http://www.pdflib.com
164
+ * @link http://www.ros.co.nz/pdf
165
+ * @link http://www.php.net/image
166
+ */
167
+ def("DOMPDF_PDF_BACKEND", "CPDF");
168
+
169
+ /**
170
+ * PDFlib license key
171
+ *
172
+ * If you are using a licensed, commercial version of PDFlib, specify
173
+ * your license key here. If you are using PDFlib-Lite or are evaluating
174
+ * the commercial version of PDFlib, comment out this setting.
175
+ *
176
+ * @link http://www.pdflib.com
177
+ *
178
+ * If pdflib present in web server and auto or selected explicitely above,
179
+ * a real license code must exist!
180
+ */
181
+ //def("DOMPDF_PDFLIB_LICENSE", "your license key here");
182
+
183
+ /**
184
+ * html target media view which should be rendered into pdf.
185
+ * List of types and parsing rules for future extensions:
186
+ * http://www.w3.org/TR/REC-html40/types.html
187
+ * screen, tty, tv, projection, handheld, print, braille, aural, all
188
+ * Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
189
+ * Note, even though the generated pdf file is intended for print output,
190
+ * the desired content might be different (e.g. screen or projection view of html file).
191
+ * Therefore allow specification of content here.
192
+ */
193
+ def("DOMPDF_DEFAULT_MEDIA_TYPE", "screen");
194
+
195
+ /**
196
+ * The default paper size.
197
+ *
198
+ * North America standard is "letter"; other countries generally "a4"
199
+ *
200
+ * @see CPDF_Adapter::PAPER_SIZES for valid sizes
201
+ */
202
+ def("DOMPDF_DEFAULT_PAPER_SIZE", "letter");
203
+
204
+ /**
205
+ * The default font family
206
+ *
207
+ * Used if no suitable fonts can be found. This must exist in the font folder.
208
+ * @var string
209
+ */
210
+ def("DOMPDF_DEFAULT_FONT", "serif");
211
+
212
+ /**
213
+ * Image DPI setting
214
+ *
215
+ * This setting determines the default DPI setting for images and fonts. The
216
+ * DPI may be overridden for inline images by explictly setting the
217
+ * image's width & height style attributes (i.e. if the image's native
218
+ * width is 600 pixels and you specify the image's width as 72 points,
219
+ * the image will have a DPI of 600 in the rendered PDF. The DPI of
220
+ * background images can not be overridden and is controlled entirely
221
+ * via this parameter.
222
+ *
223
+ * For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
224
+ * If a size in html is given as px (or without unit as image size),
225
+ * this tells the corresponding size in pt.
226
+ * This adjusts the relative sizes to be similar to the rendering of the
227
+ * html page in a reference browser.
228
+ *
229
+ * In pdf, always 1 pt = 1/72 inch
230
+ *
231
+ * Rendering resolution of various browsers in px per inch:
232
+ * Windows Firefox and Internet Explorer:
233
+ * SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
234
+ * Linux Firefox:
235
+ * about:config *resolution: Default:96
236
+ * (xorg screen dimension in mm and Desktop font dpi settings are ignored)
237
+ *
238
+ * Take care about extra font/image zoom factor of browser.
239
+ *
240
+ * In images, <img> size in pixel attribute, img css style, are overriding
241
+ * the real image dimension in px for rendering.
242
+ *
243
+ * @var int
244
+ */
245
+ def("DOMPDF_DPI", 96);
246
+
247
+ /**
248
+ * Enable inline PHP
249
+ *
250
+ * If this setting is set to true then DOMPDF will automatically evaluate
251
+ * inline PHP contained within <script type="text/php"> ... </script> tags.
252
+ *
253
+ * Enabling this for documents you do not trust (e.g. arbitrary remote html
254
+ * pages) is a security risk. Set this option to false if you wish to process
255
+ * untrusted documents.
256
+ *
257
+ * @var bool
258
+ */
259
+ def("DOMPDF_ENABLE_PHP", false);
260
+
261
+ /**
262
+ * Enable inline Javascript
263
+ *
264
+ * If this setting is set to true then DOMPDF will automatically insert
265
+ * JavaScript code contained within <script type="text/javascript"> ... </script> tags.
266
+ *
267
+ * @var bool
268
+ */
269
+ def("DOMPDF_ENABLE_JAVASCRIPT", true);
270
+
271
+ /**
272
+ * Enable remote file access
273
+ *
274
+ * If this setting is set to true, DOMPDF will access remote sites for
275
+ * images and CSS files as required.
276
+ * This is required for part of test case www/test/image_variants.html through www/examples.php
277
+ *
278
+ * Attention!
279
+ * This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and
280
+ * allowing remote access to dompdf.php or on allowing remote html code to be passed to
281
+ * $dompdf = new DOMPDF(); $dompdf->load_html(...);
282
+ * This allows anonymous users to download legally doubtful internet content which on
283
+ * tracing back appears to being downloaded by your server, or allows malicious php code
284
+ * in remote html pages to be executed by your server with your account privileges.
285
+ *
286
+ * @var bool
287
+ */
288
+ def("DOMPDF_ENABLE_REMOTE", true);
289
+
290
+ /**
291
+ * The debug output log
292
+ * @var string
293
+ */
294
+ def("DOMPDF_LOG_OUTPUT_FILE", DOMPDF_FONT_DIR."log.htm");
295
+
296
+ /**
297
+ * A ratio applied to the fonts height to be more like browsers' line height
298
+ */
299
+ def("DOMPDF_FONT_HEIGHT_RATIO", 1.1);
300
+
301
+ /**
302
+ * Enable CSS float
303
+ *
304
+ * Allows people to disabled CSS float support
305
+ * @var bool
306
+ */
307
+ def("DOMPDF_ENABLE_CSS_FLOAT", false);
308
+
309
+ /**
310
+ * Prepend the DOMPDF autoload function the spl_autoload stack
311
+ *
312
+ * @var bool
313
+ */
314
+ def("DOMPDF_AUTOLOAD_PREPEND", false);
315
+
316
+ /**
317
+ * Use the more-than-experimental HTML5 Lib parser
318
+ */
319
+ def("DOMPDF_ENABLE_HTML5PARSER", false);
320
+ require_once(DOMPDF_LIB_DIR . "/html5lib/Parser.php");
321
+
322
+ // ### End of user-configurable options ###
323
+
324
+ require_once(DOMPDF_INC_DIR . "/autoload.inc.php");
325
+
326
+ /**
327
+ * Ensure that PHP is working with text internally using UTF8 character encoding.
328
+ */
329
+ mb_internal_encoding('UTF-8');
330
+
331
+ /**
332
+ * Global array of warnings generated by DomDocument parser and
333
+ * stylesheet class
334
+ *
335
+ * @var array
336
+ */
337
+ global $_dompdf_warnings;
338
+ $_dompdf_warnings = array();
339
+
340
+ /**
341
+ * If true, $_dompdf_warnings is dumped on script termination when using
342
+ * dompdf/dompdf.php or after rendering when using the DOMPDF class.
343
+ * When using the class, setting this value to true will prevent you from
344
+ * streaming the PDF.
345
+ *
346
+ * @var bool
347
+ */
348
+ global $_dompdf_show_warnings;
349
+ $_dompdf_show_warnings = false;
350
+
351
+ /**
352
+ * If true, the entire tree is dumped to stdout in dompdf.cls.php.
353
+ * Setting this value to true will prevent you from streaming the PDF.
354
+ *
355
+ * @var bool
356
+ */
357
+ global $_dompdf_debug;
358
+ $_dompdf_debug = false;
359
+
360
+ /**
361
+ * Array of enabled debug message types
362
+ *
363
+ * @var array
364
+ */
365
+ global $_DOMPDF_DEBUG_TYPES;
366
+ $_DOMPDF_DEBUG_TYPES = array(); //array("page-break" => 1);
367
+
368
+ /* Optionally enable different classes of debug output before the pdf content.
369
+ * Visible if displaying pdf as text,
370
+ * E.g. on repeated display of same pdf in browser when pdf is not taken out of
371
+ * the browser cache and the premature output prevents setting of the mime type.
372
+ */
373
+ def('DEBUGPNG', false);
374
+ def('DEBUGKEEPTEMP', false);
375
+ def('DEBUGCSS', false);
376
+
377
+ /* Layout debugging. Will display rectangles around different block levels.
378
+ * Visible in the PDF itself.
379
+ */
380
+ def('DEBUG_LAYOUT', false);
381
+ def('DEBUG_LAYOUT_LINES', true);
382
+ def('DEBUG_LAYOUT_BLOCKS', true);
383
+ def('DEBUG_LAYOUT_INLINE', true);
384
+ def('DEBUG_LAYOUT_PADDINGBOX', true);
dompdf/include/_notes/dwsync.xml ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <dwsync>
3
+ <file name="absolute_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
4
+ <file name="abstract_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
5
+ <file name="attribute_translator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
6
+ <file name="autoload.inc.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
7
+ <file name="block_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
8
+ <file name="block_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
9
+ <file name="block_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
10
+ <file name="block_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
11
+ <file name="cached_pdf_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
12
+ <file name="canvas.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
13
+ <file name="canvas_factory.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
14
+ <file name="cellmap.cls.php" server="ftp.danielmarks.com.au" local="129908553354413613" remote="129908553000000000" />
15
+ <file name="cpdf_adapter.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
16
+ <file name="css_color.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
17
+ <file name="dompdf.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
18
+ <file name="dompdf_exception.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
19
+ <file name="dompdf_image_exception.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
20
+ <file name="file.skel" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
21
+ <file name="fixed_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
22
+ <file name="font_metrics.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
23
+ <file name="frame.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
24
+ <file name="frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
25
+ <file name="frame_factory.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
26
+ <file name="frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
27
+ <file name="frame_tree.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
28
+ <file name="functions.inc.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
29
+ <file name="gd_adapter.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
30
+ <file name="image_cache.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
31
+ <file name="image_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
32
+ <file name="image_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
33
+ <file name="image_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
34
+ <file name="inline_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
35
+ <file name="inline_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
36
+ <file name="inline_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
37
+ <file name="inline_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
38
+ <file name="javascript_embedder.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
39
+ <file name="line_box.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
40
+ <file name="list_bullet_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
41
+ <file name="list_bullet_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
42
+ <file name="list_bullet_image_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
43
+ <file name="list_bullet_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
44
+ <file name="list_bullet_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
45
+ <file name="null_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
46
+ <file name="null_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
47
+ <file name="null_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
48
+ <file name="page_cache.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
49
+ <file name="page_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
50
+ <file name="page_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
51
+ <file name="pdflib_adapter.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
52
+ <file name="php_evaluator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
53
+ <file name="positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
54
+ <file name="renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
55
+ <file name="style.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
56
+ <file name="stylesheet.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
57
+ <file name="table_cell_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
58
+ <file name="table_cell_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
59
+ <file name="table_cell_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
60
+ <file name="table_cell_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
61
+ <file name="table_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
62
+ <file name="table_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
63
+ <file name="table_row_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
64
+ <file name="table_row_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
65
+ <file name="table_row_group_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
66
+ <file name="table_row_group_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
67
+ <file name="table_row_group_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
68
+ <file name="table_row_positioner.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
69
+ <file name="tcpdf_adapter.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
70
+ <file name="text_frame_decorator.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
71
+ <file name="text_frame_reflower.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
72
+ <file name="text_renderer.cls.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
73
+ <file name="absolute_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285200000000" />
74
+ <file name="abstract_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285200000000" />
75
+ <file name="attribute_translator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285200000000" />
76
+ <file name="autoload.inc.php" server="216.235.107.57" local="129908529600000000" remote="129913285200000000" />
77
+ <file name="block_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
78
+ <file name="block_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
79
+ <file name="block_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
80
+ <file name="block_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
81
+ <file name="cached_pdf_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
82
+ <file name="canvas.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
83
+ <file name="canvas_factory.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913285800000000" />
84
+ <file name="cellmap.cls.php" server="216.235.107.57" local="129908553354413613" remote="129913286400000000" />
85
+ <file name="cpdf_adapter.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913286400000000" />
86
+ <file name="css_color.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913286400000000" />
87
+ <file name="dompdf.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913286400000000" />
88
+ <file name="dompdf_exception.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913286400000000" />
89
+ <file name="dompdf_image_exception.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913286400000000" />
90
+ <file name="file.skel" server="216.235.107.57" local="129908529600000000" remote="129913286400000000" />
91
+ <file name="fixed_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
92
+ <file name="font_metrics.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
93
+ <file name="frame.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
94
+ <file name="frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
95
+ <file name="frame_factory.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
96
+ <file name="frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
97
+ <file name="frame_tree.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287000000000" />
98
+ <file name="functions.inc.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
99
+ <file name="gd_adapter.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
100
+ <file name="image_cache.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
101
+ <file name="image_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
102
+ <file name="image_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
103
+ <file name="image_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
104
+ <file name="inline_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
105
+ <file name="inline_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913287600000000" />
106
+ <file name="inline_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
107
+ <file name="inline_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
108
+ <file name="javascript_embedder.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
109
+ <file name="line_box.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
110
+ <file name="list_bullet_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
111
+ <file name="list_bullet_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
112
+ <file name="list_bullet_image_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
113
+ <file name="list_bullet_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288200000000" />
114
+ <file name="list_bullet_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
115
+ <file name="null_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
116
+ <file name="null_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
117
+ <file name="null_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
118
+ <file name="page_cache.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
119
+ <file name="page_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
120
+ <file name="page_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
121
+ <file name="pdflib_adapter.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913288800000000" />
122
+ <file name="php_evaluator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913289400000000" />
123
+ <file name="positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913289400000000" />
124
+ <file name="renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913289400000000" />
125
+ <file name="style.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913289400000000" />
126
+ <file name="stylesheet.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913289400000000" />
127
+ <file name="table_cell_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913289400000000" />
128
+ <file name="table_cell_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
129
+ <file name="table_cell_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
130
+ <file name="table_cell_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
131
+ <file name="table_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
132
+ <file name="table_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
133
+ <file name="table_row_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
134
+ <file name="table_row_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
135
+ <file name="table_row_group_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290000000000" />
136
+ <file name="table_row_group_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
137
+ <file name="table_row_group_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
138
+ <file name="table_row_positioner.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
139
+ <file name="tcpdf_adapter.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
140
+ <file name="text_frame_decorator.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
141
+ <file name="text_frame_reflower.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
142
+ <file name="text_renderer.cls.php" server="216.235.107.57" local="129908529600000000" remote="129913290600000000" />
143
+ </dwsync>
dompdf/include/absolute_positioner.cls.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: absolute_positioner.cls.php 460 2012-01-26 07:17:46Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Positions absolutely positioned frames
12
+ */
13
+ class Absolute_Positioner extends Positioner {
14
+
15
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
16
+
17
+ function position() {
18
+
19
+ $frame = $this->_frame;
20
+ $style = $frame->get_style();
21
+
22
+ $p = $frame->find_positionned_parent();
23
+
24
+ list($x, $y, $w, $h) = $frame->get_containing_block();
25
+
26
+ $top = $style->length_in_pt($style->top, $h);
27
+ $right = $style->length_in_pt($style->right, $w);
28
+ $bottom = $style->length_in_pt($style->bottom, $h);
29
+ $left = $style->length_in_pt($style->left, $w);
30
+
31
+ if ( $p && !($left === "auto" && $right === "auto") ) {
32
+ // Get the parent's padding box (see http://www.w3.org/TR/CSS21/visuren.html#propdef-top)
33
+ list($x, $y, $w, $h) = $p->get_padding_box();
34
+ }
35
+
36
+ list($width, $height) = array($frame->get_margin_width(), $frame->get_margin_height());
37
+
38
+ $orig_style = $this->_frame->get_original_style();
39
+ $orig_width = $orig_style->width;
40
+ $orig_height = $orig_style->height;
41
+
42
+ /****************************
43
+
44
+ Width auto:
45
+ ____________| left=auto | left=fixed |
46
+ right=auto | A | B |
47
+ right=fixed | C | D |
48
+
49
+ Width fixed:
50
+ ____________| left=auto | left=fixed |
51
+ right=auto | E | F |
52
+ right=fixed | G | H |
53
+
54
+ *****************************/
55
+
56
+ if ( $left === "auto" ) {
57
+ if ( $right === "auto" ) {
58
+ // A or E - Keep the frame at the same position
59
+ }
60
+ else {
61
+ if ( $orig_width === "auto" ) {
62
+ // C
63
+ $x += $w - $width - $right;
64
+ }
65
+ else {
66
+ // G
67
+ $x += $w - $width - $right;
68
+ }
69
+ }
70
+ }
71
+ else {
72
+ if ( $right === "auto" ) {
73
+ // B or F
74
+ $x += $left;
75
+ }
76
+ else {
77
+ if ( $orig_width === "auto" ) {
78
+ // D - TODO change width
79
+ $x += $left;
80
+ }
81
+ else {
82
+ // H - Everything is fixed: left + width win
83
+ $x += $left;
84
+ }
85
+ }
86
+ }
87
+
88
+ // The same vertically
89
+ if ( $top === "auto" ) {
90
+ if ( $bottom === "auto" ) {
91
+ // A or E - Keep the frame at the same position
92
+ $y = $frame->get_parent()->get_current_line_box()->y;
93
+ }
94
+ else {
95
+ if ( $orig_height === "auto" ) {
96
+ // C
97
+ $y += $h - $height - $bottom;
98
+ }
99
+ else {
100
+ // G
101
+ $y += $h - $height - $bottom;
102
+ }
103
+ }
104
+ }
105
+ else {
106
+ if ( $bottom === "auto" ) {
107
+ // B or F
108
+ $y += $top;
109
+ }
110
+ else {
111
+ if ( $orig_height === "auto" ) {
112
+ // D - TODO change height
113
+ $y += $top;
114
+ }
115
+ else {
116
+ // H - Everything is fixed: top + height win
117
+ $y += $top;
118
+ }
119
+ }
120
+ }
121
+
122
+ $frame->set_position($x, $y);
123
+
124
+ }
125
+ }
dompdf/include/abstract_renderer.cls.php ADDED
@@ -0,0 +1,865 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: abstract_renderer.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
10
+ */
11
+
12
+ /**
13
+ * Base renderer class
14
+ *
15
+ * @access private
16
+ * @package dompdf
17
+ */
18
+ abstract class Abstract_Renderer {
19
+
20
+ /**
21
+ * Rendering backend
22
+ *
23
+ * @var Canvas
24
+ */
25
+ protected $_canvas;
26
+
27
+ /**
28
+ * Current dompdf instance
29
+ *
30
+ * @var DOMPDF
31
+ */
32
+ protected $_dompdf;
33
+
34
+ /**
35
+ * Class constructor
36
+ *
37
+ * @param DOMPDF $dompdf The current dompdf instance
38
+ */
39
+ function __construct(DOMPDF $dompdf) {
40
+ $this->_dompdf = $dompdf;
41
+ $this->_canvas = $dompdf->get_canvas();
42
+ }
43
+
44
+ /**
45
+ * Render a frame.
46
+ *
47
+ * Specialized in child classes
48
+ *
49
+ * @param Frame $frame The frame to render
50
+ */
51
+ abstract function render(Frame $frame);
52
+
53
+ //........................................................................
54
+
55
+ /**
56
+ * Render a background image over a rectangular area
57
+ *
58
+ * @param string $img The background image to load
59
+ * @param float $x The left edge of the rectangular area
60
+ * @param float $y The top edge of the rectangular area
61
+ * @param float $width The width of the rectangular area
62
+ * @param float $height The height of the rectangular area
63
+ * @param Style $style The associated Style object
64
+ */
65
+ protected function _background_image($url, $x, $y, $width, $height, $style) {
66
+ $sheet = $style->get_stylesheet();
67
+
68
+ // Skip degenerate cases
69
+ if ( $width == 0 || $height == 0 )
70
+ return;
71
+
72
+ $box_width = $width;
73
+ $box_height = $height;
74
+
75
+ //debugpng
76
+ if (DEBUGPNG) print '[_background_image '.$url.']';
77
+
78
+ list($img, $type, $msg) = Image_Cache::resolve_url($url,
79
+ $sheet->get_protocol(),
80
+ $sheet->get_host(),
81
+ $sheet->get_base_path());
82
+
83
+ // Bail if the image is no good
84
+ if ( Image_Cache::is_broken($img) )
85
+ return;
86
+
87
+ //Try to optimize away reading and composing of same background multiple times
88
+ //Postponing read with imagecreatefrom ...()
89
+ //final composition paramters and name not known yet
90
+ //Therefore read dimension directly from file, instead of creating gd object first.
91
+ //$img_w = imagesx($src); $img_h = imagesy($src);
92
+
93
+ list($img_w, $img_h) = dompdf_getimagesize($img);
94
+ if (!isset($img_w) || $img_w == 0 || !isset($img_h) || $img_h == 0) {
95
+ return;
96
+ }
97
+
98
+ $repeat = $style->background_repeat;
99
+ $bg_color = $style->background_color;
100
+
101
+ //Increase background resolution and dependent box size according to image resolution to be placed in
102
+ //Then image can be copied in without resize
103
+ $bg_width = round((float)($width * DOMPDF_DPI) / 72);
104
+ $bg_height = round((float)($height * DOMPDF_DPI) / 72);
105
+
106
+ //Need %bg_x, $bg_y as background pos, where img starts, converted to pixel
107
+
108
+ list($bg_x, $bg_y) = $style->background_position;
109
+
110
+ if ( is_percent($bg_x) ) {
111
+ // The point $bg_x % from the left edge of the image is placed
112
+ // $bg_x % from the left edge of the background rectangle
113
+ $p = ((float)$bg_x)/100.0;
114
+ $x1 = $p * $img_w;
115
+ $x2 = $p * $bg_width;
116
+
117
+ $bg_x = $x2 - $x1;
118
+ } else {
119
+ $bg_x = (float)($style->length_in_pt($bg_x)*DOMPDF_DPI) / 72;
120
+ }
121
+
122
+ $bg_x = round($bg_x + $style->length_in_pt($style->border_left_width)*DOMPDF_DPI / 72);
123
+
124
+ if ( is_percent($bg_y) ) {
125
+ // The point $bg_y % from the left edge of the image is placed
126
+ // $bg_y % from the left edge of the background rectangle
127
+ $p = ((float)$bg_y)/100.0;
128
+ $y1 = $p * $img_h;
129
+ $y2 = $p * $bg_height;
130
+
131
+ $bg_y = $y2 - $y1;
132
+ } else {
133
+ $bg_y = (float)($style->length_in_pt($bg_y)*DOMPDF_DPI) / 72;
134
+ }
135
+
136
+ $bg_y = round($bg_y + $style->length_in_pt($style->border_top_width)*DOMPDF_DPI / 72);
137
+
138
+ //clip background to the image area on partial repeat. Nothing to do if img off area
139
+ //On repeat, normalize start position to the tile at immediate left/top or 0/0 of area
140
+ //On no repeat with positive offset: move size/start to have offset==0
141
+ //Handle x/y Dimensions separately
142
+
143
+ if ( $repeat !== "repeat" && $repeat !== "repeat-x" ) {
144
+ //No repeat x
145
+ if ($bg_x < 0) {
146
+ $bg_width = $img_w + $bg_x;
147
+ } else {
148
+ $x += ($bg_x * 72)/DOMPDF_DPI;
149
+ $bg_width = $bg_width - $bg_x;
150
+ if ($bg_width > $img_w) {
151
+ $bg_width = $img_w;
152
+ }
153
+ $bg_x = 0;
154
+ }
155
+ if ($bg_width <= 0) {
156
+ return;
157
+ }
158
+ $width = (float)($bg_width * 72)/DOMPDF_DPI;
159
+ } else {
160
+ //repeat x
161
+ if ($bg_x < 0) {
162
+ $bg_x = - ((-$bg_x) % $img_w);
163
+ } else {
164
+ $bg_x = $bg_x % $img_w;
165
+ if ($bg_x > 0) {
166
+ $bg_x -= $img_w;
167
+ }
168
+ }
169
+ }
170
+
171
+ if ( $repeat !== "repeat" && $repeat !== "repeat-y" ) {
172
+ //no repeat y
173
+ if ($bg_y < 0) {
174
+ $bg_height = $img_h + $bg_y;
175
+ } else {
176
+ $y += ($bg_y * 72)/DOMPDF_DPI;
177
+ $bg_height = $bg_height - $bg_y;
178
+ if ($bg_height > $img_h) {
179
+ $bg_height = $img_h;
180
+ }
181
+ $bg_y = 0;
182
+ }
183
+ if ($bg_height <= 0) {
184
+ return;
185
+ }
186
+ $height = (float)($bg_height * 72)/DOMPDF_DPI;
187
+ } else {
188
+ //repeat y
189
+ if ($bg_y < 0) {
190
+ $bg_y = - ((-$bg_y) % $img_h);
191
+ } else {
192
+ $bg_y = $bg_y % $img_h;
193
+ if ($bg_y > 0) {
194
+ $bg_y -= $img_h;
195
+ }
196
+ }
197
+ }
198
+
199
+ //Optimization, if repeat has no effect
200
+ if ( $repeat === "repeat" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height ) {
201
+ $repeat = "repeat-x";
202
+ }
203
+ if ( $repeat === "repeat" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width ) {
204
+ $repeat = "repeat-y";
205
+ }
206
+ if ( ($repeat === "repeat-x" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width) ||
207
+ ($repeat === "repeat-y" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height) ) {
208
+ $repeat = "no-repeat";
209
+ }
210
+
211
+ //Use filename as indicator only
212
+ //different names for different variants to have different copies in the pdf
213
+ //This is not dependent of background color of box! .'_'.(is_array($bg_color) ? $bg_color["hex"] : $bg_color)
214
+ //Note: Here, bg_* are the start values, not end values after going through the tile loops!
215
+
216
+ $filedummy = $img;
217
+
218
+ /*
219
+ //Make shorter strings with limited characters for cache associative array index - needed?
220
+ //Strip common base path - server root, explicite temp, default temp; remove unwanted characters;
221
+ $filedummy = strtr($filedummy,"\\:","//");
222
+ $p = strtr($_SERVER["DOCUMENT_ROOT"],"\\:","//");
223
+ $l = strlen($p);
224
+ if ( substr($filedummy,0,$l) == $p) {
225
+ $filedummy = substr($filedummy,$l);
226
+ } else {
227
+ $p = strtr(DOMPDF_TEMP_DIR,"\\:","//");
228
+ $l = strlen($p);
229
+ if ( substr($filedummy,0,$l) == $p) {
230
+ $filedummy = substr($filedummy,$l);
231
+ } else {
232
+ $p = strtr(sys_get_temp_dir(),"\\:","//");
233
+ $l = strlen($p);
234
+ if ( substr($filedummy,0,$l) == $p) {
235
+ $filedummy = substr($filedummy,$l);
236
+ }
237
+ }
238
+ }
239
+ */
240
+
241
+ $is_png = false;
242
+ $filedummy .= '_'.$bg_width.'_'.$bg_height.'_'.$bg_x.'_'.$bg_y.'_'.$repeat;
243
+ //debugpng
244
+ //if (DEBUGPNG) print '<pre>[_background_image name '.$filedummy.']</pre>';
245
+
246
+ //Optimization to avoid multiple times rendering the same image.
247
+ //If check functions are existing and identical image already cached,
248
+ //then skip creation of duplicate, because it is not needed by addImagePng
249
+ if ( method_exists( $this->_canvas, "get_cpdf" ) &&
250
+ method_exists( $this->_canvas->get_cpdf(), "addImagePng" ) &&
251
+ method_exists( $this->_canvas->get_cpdf(), "image_iscached" ) &&
252
+ $this->_canvas->get_cpdf()->image_iscached($filedummy) ) {
253
+ $bg = null;
254
+
255
+ //debugpng
256
+ //if (DEBUGPNG) print '[_background_image skip]';
257
+ }
258
+
259
+ else {
260
+
261
+ // Create a new image to fit over the background rectangle
262
+ $bg = imagecreatetruecolor($bg_width, $bg_height);
263
+
264
+ switch (strtolower($type)) {
265
+ case IMAGETYPE_PNG:
266
+ $is_png = true;
267
+ imagesavealpha($bg, true);
268
+ imagealphablending($bg, false);
269
+ $src = imagecreatefrompng($img);
270
+ break;
271
+
272
+ case IMAGETYPE_JPEG:
273
+ $src = imagecreatefromjpeg($img);
274
+ break;
275
+
276
+ case IMAGETYPE_GIF:
277
+ $src = imagecreatefromgif($img);
278
+ break;
279
+
280
+ case IMAGETYPE_BMP:
281
+ $src = imagecreatefrombmp($img);
282
+ break;
283
+
284
+ default: return; // Unsupported image type
285
+ }
286
+
287
+ if ($src == null) {
288
+ return;
289
+ }
290
+
291
+ //Background color if box is not relevant here
292
+ //Non transparent image: box clipped to real size. Background non relevant.
293
+ //Transparent image: The image controls the transparency and lets shine through whatever background.
294
+ //However on transparent imaage preset the composed image with the transparency color,
295
+ //to keep the transparency when copying over the non transparent parts of the tiles.
296
+ $ti = imagecolortransparent($src);
297
+
298
+ if ($ti >= 0) {
299
+ $tc = imagecolorsforindex($src,$ti);
300
+ $ti = imagecolorallocate($bg,$tc['red'],$tc['green'],$tc['blue']);
301
+ imagefill($bg,0,0,$ti);
302
+ imagecolortransparent($bg, $ti);
303
+ }
304
+
305
+ //This has only an effect for the non repeatable dimension.
306
+ //compute start of src and dest coordinates of the single copy
307
+ if ( $bg_x < 0 ) {
308
+ $dst_x = 0;
309
+ $src_x = -$bg_x;
310
+ } else {
311
+ $src_x = 0;
312
+ $dst_x = $bg_x;
313
+ }
314
+
315
+ if ( $bg_y < 0 ) {
316
+ $dst_y = 0;
317
+ $src_y = -$bg_y;
318
+ } else {
319
+ $src_y = 0;
320
+ $dst_y = $bg_y;
321
+ }
322
+
323
+ //For historical reasons exchange meanings of variables:
324
+ //start_* will be the start values, while bg_* will be the temporary start values in the loops
325
+ $start_x = $bg_x;
326
+ $start_y = $bg_y;
327
+
328
+ // Copy regions from the source image to the background
329
+ if ( $repeat === "no-repeat" ) {
330
+
331
+ // Simply place the image on the background
332
+ imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h);
333
+
334
+ } else if ( $repeat === "repeat-x" ) {
335
+
336
+ for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) {
337
+ if ( $bg_x < 0 ) {
338
+ $dst_x = 0;
339
+ $src_x = -$bg_x;
340
+ $w = $img_w + $bg_x;
341
+ } else {
342
+ $dst_x = $bg_x;
343
+ $src_x = 0;
344
+ $w = $img_w;
345
+ }
346
+ imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h);
347
+ }
348
+
349
+ } else if ( $repeat === "repeat-y" ) {
350
+
351
+ for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) {
352
+ if ( $bg_y < 0 ) {
353
+ $dst_y = 0;
354
+ $src_y = -$bg_y;
355
+ $h = $img_h + $bg_y;
356
+ } else {
357
+ $dst_y = $bg_y;
358
+ $src_y = 0;
359
+ $h = $img_h;
360
+ }
361
+ imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h);
362
+
363
+ }
364
+
365
+ } else if ( $repeat === "repeat" ) {
366
+
367
+ for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) {
368
+ for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) {
369
+
370
+ if ( $bg_x < 0 ) {
371
+ $dst_x = 0;
372
+ $src_x = -$bg_x;
373
+ $w = $img_w + $bg_x;
374
+ } else {
375
+ $dst_x = $bg_x;
376
+ $src_x = 0;
377
+ $w = $img_w;
378
+ }
379
+
380
+ if ( $bg_y < 0 ) {
381
+ $dst_y = 0;
382
+ $src_y = -$bg_y;
383
+ $h = $img_h + $bg_y;
384
+ } else {
385
+ $dst_y = $bg_y;
386
+ $src_y = 0;
387
+ $h = $img_h;
388
+ }
389
+ imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $h);
390
+ }
391
+ }
392
+ }
393
+
394
+ else {
395
+ print 'Unknown repeat!';
396
+ }
397
+
398
+ imagedestroy($src);
399
+
400
+ } /* End optimize away creation of duplicates */
401
+
402
+ $this->_canvas->clipping_rectangle($x, $y, $box_width, $box_height);
403
+
404
+ //img: image url string
405
+ //img_w, img_h: original image size in px
406
+ //width, height: box size in pt
407
+ //bg_width, bg_height: box size in px
408
+ //x, y: left/top edge of box on page in pt
409
+ //start_x, start_y: placement of image relativ to pattern
410
+ //$repeat: repeat mode
411
+ //$bg: GD object of result image
412
+ //$src: GD object of original image
413
+ //When using cpdf and optimization to direct png creation from gd object is available,
414
+ //don't create temp file, but place gd object directly into the pdf
415
+ if ( !$is_png && method_exists( $this->_canvas, "get_cpdf" ) &&
416
+ method_exists( $this->_canvas->get_cpdf(), "addImagePng" ) ) {
417
+ // Note: CPDF_Adapter image converts y position
418
+ $this->_canvas->get_cpdf()->addImagePng($filedummy, $x, $this->_canvas->get_height() - $y - $height, $width, $height, $bg);
419
+ }
420
+
421
+ else {
422
+ $tmp_name = tempnam(DOMPDF_TEMP_DIR, "bg_dompdf_img_");
423
+ @unlink($tmp_name);
424
+ $tmp_file = "$tmp_name.png";
425
+
426
+ //debugpng
427
+ if (DEBUGPNG) print '[_background_image '.$tmp_file.']';
428
+
429
+ imagepng($bg, $tmp_file);
430
+ $this->_canvas->image($tmp_file, $x, $y, $width, $height);
431
+ imagedestroy($bg);
432
+
433
+ //debugpng
434
+ if (DEBUGPNG) print '[_background_image unlink '.$tmp_file.']';
435
+
436
+ if (!DEBUGKEEPTEMP)
437
+ unlink($tmp_file);
438
+ }
439
+
440
+ $this->_canvas->clipping_end();
441
+ }
442
+
443
+ protected function _get_dash_pattern($style, $width) {
444
+ $pattern = array();
445
+
446
+ switch ($style) {
447
+ default:
448
+ /*case "solid":
449
+ case "double":
450
+ case "groove":
451
+ case "inset":
452
+ case "outset":
453
+ case "ridge":*/
454
+ case "none": break;
455
+
456
+ case "dotted":
457
+ if ( $width <= 1 )
458
+ $pattern = array($width, $width*2);
459
+ else
460
+ $pattern = array($width);
461
+ break;
462
+
463
+ case "dashed":
464
+ $pattern = array(3 * $width);
465
+ break;
466
+ }
467
+
468
+ return $pattern;
469
+ }
470
+
471
+ protected function _border_none($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
472
+ return;
473
+ }
474
+
475
+ protected function _border_hidden($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
476
+ return;
477
+ }
478
+
479
+ // Border rendering functions
480
+ protected function _border_dotted($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
481
+ list($top, $right, $bottom, $left) = $widths;
482
+
483
+ $pattern = $this->_get_dash_pattern("dotted", $$side);
484
+
485
+ switch ($side) {
486
+
487
+ case "top":
488
+ $delta = $top / 2;
489
+ case "bottom":
490
+ $delta = isset($delta) ? $delta : -$bottom / 2;
491
+ $this->_canvas->line($x, $y + $delta, $x + $length, $y + $delta, $color, $$side, $pattern);
492
+ break;
493
+
494
+ case "left":
495
+ $delta = $left / 2;
496
+ case "right":
497
+ $delta = isset($delta) ? $delta : - $right / 2;
498
+ $this->_canvas->line($x + $delta, $y, $x + $delta, $y + $length, $color, $$side, $pattern);
499
+ break;
500
+
501
+ default:
502
+ return;
503
+
504
+ }
505
+ }
506
+
507
+
508
+ protected function _border_dashed($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
509
+ list($top, $right, $bottom, $left) = $widths;
510
+
511
+ $pattern = $this->_get_dash_pattern("dashed", $$side);
512
+
513
+ switch ($side) {
514
+
515
+ case "top":
516
+ $delta = $top / 2;
517
+ case "bottom":
518
+ $delta = isset($delta) ? $delta : -$bottom / 2;
519
+ $this->_canvas->line($x, $y + $delta, $x + $length, $y + $delta, $color, $$side, $pattern);
520
+ break;
521
+
522
+ case "left":
523
+ $delta = $left / 2;
524
+ case "right":
525
+ $delta = isset($delta) ? $delta : - $right / 2;
526
+ $this->_canvas->line($x + $delta, $y, $x + $delta, $y + $length, $color, $$side, $pattern);
527
+ break;
528
+
529
+ default:
530
+ return;
531
+ }
532
+
533
+ }
534
+
535
+
536
+ protected function _border_solid($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
537
+ list($top, $right, $bottom, $left) = $widths;
538
+
539
+ // All this polygon business is for beveled corners...
540
+ switch ($side) {
541
+
542
+ case "top":
543
+ if ( $corner_style === "bevel" ) {
544
+
545
+ $points = array($x, $y,
546
+ $x + $length, $y,
547
+ $x + $length - $right, $y + $top,
548
+ $x + $left, $y + $top);
549
+ $this->_canvas->polygon($points, $color, null, null, true);
550
+ } else
551
+ $this->_canvas->filled_rectangle($x, $y, $length, $top, $color);
552
+
553
+ break;
554
+
555
+ case "bottom":
556
+ if ( $corner_style === "bevel" ) {
557
+ $points = array($x, $y,
558
+ $x + $length, $y,
559
+ $x + $length - $right, $y - $bottom,
560
+ $x + $left, $y - $bottom);
561
+ $this->_canvas->polygon($points, $color, null, null, true);
562
+ } else
563
+ $this->_canvas->filled_rectangle($x, $y - $bottom, $length, $bottom, $color);
564
+
565
+ break;
566
+
567
+ case "left":
568
+ if ( $corner_style === "bevel" ) {
569
+ $points = array($x, $y,
570
+ $x, $y + $length,
571
+ $x + $left, $y + $length - $bottom,
572
+ $x + $left, $y + $top);
573
+ $this->_canvas->polygon($points, $color, null, null, true);
574
+ } else
575
+ $this->_canvas->filled_rectangle($x, $y, $left, $length, $color);
576
+
577
+ break;
578
+
579
+ case "right":
580
+ if ( $corner_style === "bevel" ) {
581
+ $points = array($x, $y,
582
+ $x, $y + $length,
583
+ $x - $right, $y + $length - $bottom,
584
+ $x - $right, $y + $top);
585
+ $this->_canvas->polygon($points, $color, null, null, true);
586
+ } else
587
+ $this->_canvas->filled_rectangle($x - $right, $y, $right, $length, $color);
588
+
589
+ break;
590
+
591
+ default:
592
+ return;
593
+
594
+ }
595
+
596
+ }
597
+
598
+
599
+ protected function _border_double($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
600
+ list($top, $right, $bottom, $left) = $widths;
601
+
602
+ $line_width = $$side / 3;
603
+
604
+ // We draw the outermost edge first. Points are ordered: outer left,
605
+ // outer right, inner right, inner left, or outer top, outer bottom,
606
+ // inner bottom, inner top.
607
+ switch ($side) {
608
+
609
+ case "top":
610
+ if ( $corner_style === "bevel" ) {
611
+ $left_line_width = $left / 3;
612
+ $right_line_width = $right / 3;
613
+
614
+ $points = array($x, $y,
615
+ $x + $length, $y,
616
+ $x + $length - $right_line_width, $y + $line_width,
617
+ $x + $left_line_width, $y + $line_width,);
618
+ $this->_canvas->polygon($points, $color, null, null, true);
619
+
620
+ $points = array($x + $left - $left_line_width, $y + $top - $line_width,
621
+ $x + $length - $right + $right_line_width, $y + $top - $line_width,
622
+ $x + $length - $right, $y + $top,
623
+ $x + $left, $y + $top);
624
+ $this->_canvas->polygon($points, $color, null, null, true);
625
+
626
+ } else {
627
+ $this->_canvas->filled_rectangle($x, $y, $length, $line_width, $color);
628
+ $this->_canvas->filled_rectangle($x, $y + $top - $line_width, $length, $line_width, $color);
629
+
630
+ }
631
+ break;
632
+
633
+ case "bottom":
634
+ if ( $corner_style === "bevel" ) {
635
+ $left_line_width = $left / 3;
636
+ $right_line_width = $right / 3;
637
+
638
+ $points = array($x, $y,
639
+ $x + $length, $y,
640
+ $x + $length - $right_line_width, $y - $line_width,
641
+ $x + $left_line_width, $y - $line_width);
642
+ $this->_canvas->polygon($points, $color, null, null, true);
643
+
644
+ $points = array($x + $left - $left_line_width, $y - $bottom + $line_width,
645
+ $x + $length - $right + $right_line_width, $y - $bottom + $line_width,
646
+ $x + $length - $right, $y - $bottom,
647
+ $x + $left, $y - $bottom);
648
+ $this->_canvas->polygon($points, $color, null, null, true);
649
+
650
+ } else {
651
+ $this->_canvas->filled_rectangle($x, $y - $line_width, $length, $line_width, $color);
652
+ $this->_canvas->filled_rectangle($x, $y - $bottom, $length, $line_width, $color);
653
+ }
654
+
655
+ break;
656
+
657
+ case "left":
658
+ if ( $corner_style === "bevel" ) {
659
+ $top_line_width = $top / 3;
660
+ $bottom_line_width = $bottom / 3;
661
+
662
+ $points = array($x, $y,
663
+ $x, $y + $length,
664
+ $x + $line_width, $y + $length - $bottom_line_width,
665
+ $x + $line_width, $y + $top_line_width);
666
+ $this->_canvas->polygon($points, $color, null, null, true);
667
+
668
+ $points = array($x + $left - $line_width, $y + $top - $top_line_width,
669
+ $x + $left - $line_width, $y + $length - $bottom + $bottom_line_width,
670
+ $x + $left, $y + $length - $bottom,
671
+ $x + $left, $y + $top);
672
+ $this->_canvas->polygon($points, $color, null, null, true);
673
+
674
+ } else {
675
+ $this->_canvas->filled_rectangle($x, $y, $line_width, $length, $color);
676
+ $this->_canvas->filled_rectangle($x + $left - $line_width, $y, $line_width, $length, $color);
677
+ }
678
+
679
+ break;
680
+
681
+ case "right":
682
+ if ( $corner_style === "bevel" ) {
683
+ $top_line_width = $top / 3;
684
+ $bottom_line_width = $bottom / 3;
685
+
686
+
687
+ $points = array($x, $y,
688
+ $x, $y + $length,
689
+ $x - $line_width, $y + $length - $bottom_line_width,
690
+ $x - $line_width, $y + $top_line_width);
691
+ $this->_canvas->polygon($points, $color, null, null, true);
692
+
693
+ $points = array($x - $right + $line_width, $y + $top - $top_line_width,
694
+ $x - $right + $line_width, $y + $length - $bottom + $bottom_line_width,
695
+ $x - $right, $y + $length - $bottom,
696
+ $x - $right, $y + $top);
697
+ $this->_canvas->polygon($points, $color, null, null, true);
698
+
699
+ } else {
700
+ $this->_canvas->filled_rectangle($x - $line_width, $y, $line_width, $length, $color);
701
+ $this->_canvas->filled_rectangle($x - $right, $y, $line_width, $length, $color);
702
+ }
703
+
704
+ break;
705
+
706
+ default:
707
+ return;
708
+
709
+ }
710
+
711
+ }
712
+
713
+ protected function _border_groove($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
714
+ list($top, $right, $bottom, $left) = $widths;
715
+
716
+ $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2);
717
+
718
+ $this->_border_inset($x, $y, $length, $color, $half_widths, $side);
719
+
720
+ switch ($side) {
721
+
722
+ case "top":
723
+ $x += $left / 2;
724
+ $y += $top / 2;
725
+ $length -= $left / 2 + $right / 2;
726
+ break;
727
+
728
+ case "bottom":
729
+ $x += $left / 2;
730
+ $y -= $bottom / 2;
731
+ $length -= $left / 2 + $right / 2;
732
+ break;
733
+
734
+ case "left":
735
+ $x += $left / 2;
736
+ $y += $top / 2;
737
+ $length -= $top / 2 + $bottom / 2;
738
+ break;
739
+
740
+ case "right":
741
+ $x -= $right / 2;
742
+ $y += $top / 2;
743
+ $length -= $top / 2 + $bottom / 2;
744
+ break;
745
+
746
+ default:
747
+ return;
748
+
749
+ }
750
+
751
+ $this->_border_outset($x, $y, $length, $color, $half_widths, $side);
752
+
753
+ }
754
+
755
+ protected function _border_ridge($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
756
+ list($top, $right, $bottom, $left) = $widths;
757
+
758
+ $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2);
759
+
760
+ $this->_border_outset($x, $y, $length, $color, $half_widths, $side);
761
+
762
+ switch ($side) {
763
+
764
+ case "top":
765
+ $x += $left / 2;
766
+ $y += $top / 2;
767
+ $length -= $left / 2 + $right / 2;
768
+ break;
769
+
770
+ case "bottom":
771
+ $x += $left / 2;
772
+ $y -= $bottom / 2;
773
+ $length -= $left / 2 + $right / 2;
774
+ break;
775
+
776
+ case "left":
777
+ $x += $left / 2;
778
+ $y += $top / 2;
779
+ $length -= $top / 2 + $bottom / 2;
780
+ break;
781
+
782
+ case "right":
783
+ $x -= $right / 2;
784
+ $y += $top / 2;
785
+ $length -= $top / 2 + $bottom / 2;
786
+ break;
787
+
788
+ default:
789
+ return;
790
+
791
+ }
792
+
793
+ $this->_border_inset($x, $y, $length, $color, $half_widths, $side);
794
+
795
+ }
796
+
797
+ protected function _tint($c) {
798
+ if ( !is_numeric($c) )
799
+ return $c;
800
+
801
+ return min(1, $c + 0.16);
802
+ }
803
+
804
+ protected function _shade($c) {
805
+ if ( !is_numeric($c) )
806
+ return $c;
807
+
808
+ return max(0, $c - 0.33);
809
+ }
810
+
811
+ protected function _border_inset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
812
+ list($top, $right, $bottom, $left) = $widths;
813
+
814
+ switch ($side) {
815
+
816
+ case "top":
817
+ case "left":
818
+ $shade = array_map(array($this, "_shade"), $color);
819
+ $this->_border_solid($x, $y, $length, $shade, $widths, $side);
820
+ break;
821
+
822
+ case "bottom":
823
+ case "right":
824
+ $tint = array_map(array($this, "_tint"), $color);
825
+ $this->_border_solid($x, $y, $length, $tint, $widths, $side);
826
+ break;
827
+
828
+ default:
829
+ return;
830
+ }
831
+ }
832
+
833
+ protected function _border_outset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
834
+ list($top, $right, $bottom, $left) = $widths;
835
+
836
+ switch ($side) {
837
+ case "top":
838
+ case "left":
839
+ $tint = array_map(array($this, "_tint"), $color);
840
+ $this->_border_solid($x, $y, $length, $tint, $widths, $side);
841
+ break;
842
+
843
+ case "bottom":
844
+ case "right":
845
+ $shade = array_map(array($this, "_shade"), $color);
846
+ $this->_border_solid($x, $y, $length, $shade, $widths, $side);
847
+ break;
848
+
849
+ default:
850
+ return;
851
+
852
+ }
853
+ }
854
+
855
+ protected function _set_opacity($opacity) {
856
+ if ( is_numeric($opacity) && $opacity <= 1.0 && $opacity >= 0.0 ) {
857
+ $this->_canvas->set_opacity( $opacity );
858
+ }
859
+ }
860
+
861
+ protected function _debug_layout($box, $color = "red", $style = array()) {
862
+ $this->_canvas->rectangle($box[0], $box[1], $box[2], $box[3], CSS_Color::parse($color), 0.1, $style);
863
+ }
864
+ //........................................................................
865
+ }
dompdf/include/attribute_translator.cls.php ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: attribute_translator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Translates HTML 4.0 attributes into CSS rules
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Attribute_Translator {
18
+ static $_style_attr = "_html_style_attribute";
19
+
20
+ // Munged data originally from
21
+ // http://www.w3.org/TR/REC-html40/index/attributes.html
22
+ // http://www.cs.tut.fi/~jkorpela/html2css.html
23
+ static private $__ATTRIBUTE_LOOKUP = array(
24
+ //'caption' => array ( 'align' => '', ),
25
+ 'img' => array(
26
+ 'align' => array(
27
+ 'bottom' => 'vertical-align: baseline;',
28
+ 'middle' => 'vertical-align: middle;',
29
+ 'top' => 'vertical-align: top;',
30
+ 'left' => 'float: left;',
31
+ 'right' => 'float: right;'
32
+ ),
33
+ 'border' => 'border-width: %0.2F px;',
34
+ 'height' => 'height: %s px;',
35
+ 'hspace' => 'padding-left: %1$0.2F px; padding-right: %1$0.2F px;',
36
+ 'vspace' => 'padding-top: %1$0.2F px; padding-bottom: %1$0.2F px;',
37
+ 'width' => 'width: %s px;',
38
+ ),
39
+ 'table' => array(
40
+ 'align' => array(
41
+ 'left' => 'margin-left: 0; margin-right: auto;',
42
+ 'center' => 'margin-left: auto; margin-right: auto;',
43
+ 'right' => 'margin-left: auto; margin-right: 0;'
44
+ ),
45
+ 'bgcolor' => 'background-color: %s;',
46
+ 'border' => '!set_table_border',
47
+ 'cellpadding' => '!set_table_cellpadding',//'border-spacing: %0.2F; border-collapse: separate;',
48
+ 'cellspacing' => '!set_table_cellspacing',
49
+ 'frame' => array(
50
+ 'void' => 'border-style: none;',
51
+ 'above' => 'border-top-style: solid;',
52
+ 'below' => 'border-bottom-style: solid;',
53
+ 'hsides' => 'border-left-style: solid; border-right-style: solid;',
54
+ 'vsides' => 'border-top-style: solid; border-bottom-style: solid;',
55
+ 'lhs' => 'border-left-style: solid;',
56
+ 'rhs' => 'border-right-style: solid;',
57
+ 'box' => 'border-style: solid;',
58
+ 'border' => 'border-style: solid;'
59
+ ),
60
+ 'rules' => '!set_table_rules',
61
+ 'width' => 'width: %s;',
62
+ ),
63
+ 'hr' => array(
64
+ 'align' => '!set_hr_align', // Need to grab width to set 'left' & 'right' correctly
65
+ 'noshade' => 'border-style: solid;',
66
+ 'size' => '!set_hr_size', //'border-width: %0.2F px;',
67
+ 'width' => 'width: %s;',
68
+ ),
69
+ 'div' => array(
70
+ 'align' => 'text-align: %s;',
71
+ ),
72
+ 'h1' => array(
73
+ 'align' => 'text-align: %s;',
74
+ ),
75
+ 'h2' => array(
76
+ 'align' => 'text-align: %s;',
77
+ ),
78
+ 'h3' => array(
79
+ 'align' => 'text-align: %s;',
80
+ ),
81
+ 'h4' => array(
82
+ 'align' => 'text-align: %s;',
83
+ ),
84
+ 'h5' => array(
85
+ 'align' => 'text-align: %s;',
86
+ ),
87
+ 'h6' => array(
88
+ 'align' => 'text-align: %s;',
89
+ ),
90
+ 'p' => array(
91
+ 'align' => 'text-align: %s;',
92
+ ),
93
+ // 'col' => array(
94
+ // 'align' => '',
95
+ // 'valign' => '',
96
+ // ),
97
+ // 'colgroup' => array(
98
+ // 'align' => '',
99
+ // 'valign' => '',
100
+ // ),
101
+ 'tbody' => array(
102
+ 'align' => '!set_table_row_align',
103
+ 'valign' => '!set_table_row_valign',
104
+ ),
105
+ 'td' => array(
106
+ 'align' => 'text-align: %s;',
107
+ 'bgcolor' => '!set_background_color',
108
+ 'height' => 'height: %s;',
109
+ 'nowrap' => 'white-space: nowrap;',
110
+ 'valign' => 'vertical-align: %s;',
111
+ 'width' => 'width: %s;',
112
+ ),
113
+ 'tfoot' => array(
114
+ 'align' => '!set_table_row_align',
115
+ 'valign' => '!set_table_row_valign',
116
+ ),
117
+ 'th' => array(
118
+ 'align' => 'text-align: %s;',
119
+ 'bgcolor' => '!set_background_color',
120
+ 'height' => 'height: %s;',
121
+ 'nowrap' => 'white-space: nowrap;',
122
+ 'valign' => 'vertical-align: %s;',
123
+ 'width' => 'width: %s;',
124
+ ),
125
+ 'thead' => array(
126
+ 'align' => '!set_table_row_align',
127
+ 'valign' => '!set_table_row_valign',
128
+ ),
129
+ 'tr' => array(
130
+ 'align' => '!set_table_row_align',
131
+ 'bgcolor' => '!set_table_row_bgcolor',
132
+ 'valign' => '!set_table_row_valign',
133
+ ),
134
+ 'body' => array(
135
+ 'background' => 'background-image: url(%s);',
136
+ 'bgcolor' => '!set_background_color',
137
+ 'link' => '!set_body_link',
138
+ 'text' => '!set_color',
139
+ ),
140
+ 'br' => array(
141
+ 'clear' => 'clear: %s;',
142
+ ),
143
+ 'basefont' => array(
144
+ 'color' => '!set_color',
145
+ 'face' => 'font-family: %s;',
146
+ 'size' => '!set_basefont_size',
147
+ ),
148
+ 'font' => array(
149
+ 'color' => '!set_color',
150
+ 'face' => 'font-family: %s;',
151
+ 'size' => '!set_font_size',
152
+ ),
153
+ 'dir' => array(
154
+ 'compact' => 'margin: 0.5em 0;',
155
+ ),
156
+ 'dl' => array(
157
+ 'compact' => 'margin: 0.5em 0;',
158
+ ),
159
+ 'menu' => array(
160
+ 'compact' => 'margin: 0.5em 0;',
161
+ ),
162
+ 'ol' => array(
163
+ 'compact' => 'margin: 0.5em 0;',
164
+ 'start' => 'counter-reset: -dompdf-default-counter %d;',
165
+ 'type' => 'list-style-type: %s;',
166
+ ),
167
+ 'ul' => array(
168
+ 'compact' => 'margin: 0.5em 0;',
169
+ 'type' => 'list-style-type: %s;',
170
+ ),
171
+ 'li' => array(
172
+ 'type' => 'list-style-type: %s;',
173
+ 'value' => 'counter-reset: -dompdf-default-counter %d;',
174
+ ),
175
+ 'pre' => array(
176
+ 'width' => 'width: %s;',
177
+ ),
178
+ );
179
+
180
+ static protected $_last_basefont_size = 3;
181
+ static protected $_font_size_lookup = array(
182
+ // For basefont support
183
+ -3 => "4pt",
184
+ -2 => "5pt",
185
+ -1 => "6pt",
186
+ 0 => "7pt",
187
+
188
+ 1 => "8pt",
189
+ 2 => "10pt",
190
+ 3 => "12pt",
191
+ 4 => "14pt",
192
+ 5 => "18pt",
193
+ 6 => "24pt",
194
+ 7 => "34pt",
195
+
196
+ // For basefont support
197
+ 8 => "48pt",
198
+ 9 => "44pt",
199
+ 10 => "52pt",
200
+ 11 => "60pt",
201
+ );
202
+
203
+
204
+ static function translate_attributes(Frame $frame) {
205
+ $node = $frame->get_node();
206
+ $tag = $node->tagName;
207
+
208
+ if ( !isset(self::$__ATTRIBUTE_LOOKUP[$tag]) )
209
+ return;
210
+
211
+ $valid_attrs = self::$__ATTRIBUTE_LOOKUP[$tag];
212
+ $attrs = $node->attributes;
213
+ $style = rtrim($node->getAttribute(self::$_style_attr), "; ");
214
+ if ( $style != "" )
215
+ $style .= ";";
216
+
217
+ foreach ($attrs as $attr => $attr_node ) {
218
+ if ( !isset($valid_attrs[$attr]) )
219
+ continue;
220
+
221
+ $value = $attr_node->value;
222
+
223
+ $target = $valid_attrs[$attr];
224
+
225
+ // Look up $value in $target, if $target is an array:
226
+ if ( is_array($target) ) {
227
+
228
+ if ( isset($target[$value]) )
229
+ $style .= " " . self::_resolve_target($node, $target[$value], $value);
230
+
231
+ } else {
232
+ // otherwise use target directly
233
+ $style .= " " . self::_resolve_target($node, $target, $value);
234
+ }
235
+ }
236
+
237
+ if ( !is_null($style) ) {
238
+ $style = ltrim($style);
239
+ $node->setAttribute(self::$_style_attr, $style);
240
+ }
241
+
242
+ }
243
+
244
+ static protected function _resolve_target($node, $target, $value) {
245
+ if ( $target[0] === "!" ) {
246
+ // Function call
247
+ $func = "_" . mb_substr($target, 1);
248
+ return self::$func($node, $value);
249
+ }
250
+
251
+ return $value ? sprintf($target, $value) : "";
252
+ }
253
+
254
+ static function append_style(DOMNode $node, $new_style) {
255
+ $style = rtrim($node->getAttribute(self::$_style_attr), ";");
256
+ $style .= $new_style;
257
+ $style = ltrim($style, ";");
258
+ $node->setAttribute(self::$_style_attr, $style);
259
+ }
260
+
261
+ static protected function get_cell_list($node) {
262
+ $xpath = new DOMXpath($node->ownerDocument);
263
+
264
+ switch($node->nodeName) {
265
+ case "table":
266
+ $query = "tr/td | thead/tr/td | tbody/tr/td | tfoot/tr/td | tr/th | thead/tr/th | tbody/tr/th | tfoot/tr/th";
267
+ break;
268
+
269
+ case "tbody":
270
+ case "tfoot":
271
+ case "thead":
272
+ $query = "tr/td | tr/th";
273
+ break;
274
+
275
+ case "tr":
276
+ $query = "td | th";
277
+ break;
278
+ }
279
+
280
+ return $xpath->query($query, $node);
281
+ }
282
+
283
+ //.....................................................................
284
+
285
+ static protected function _get_valid_color($value) {
286
+ if ( preg_match('/^#?([0-9A-F]{6})$/i', $value, $matches) ) {
287
+ $value = "#$matches[1]";
288
+ }
289
+
290
+ return $value;
291
+ }
292
+
293
+ static protected function _set_color($node, $value) {
294
+ $value = self::_get_valid_color($value);
295
+ return "color: $value;";
296
+ }
297
+
298
+ static protected function _set_background_color($node, $value) {
299
+ $value = self::_get_valid_color($value);
300
+ return "background-color: $value;";
301
+ }
302
+
303
+ static protected function _set_table_cellpadding($node, $value) {
304
+ $cell_list = self::get_cell_list($node);
305
+
306
+ foreach ($cell_list as $cell) {
307
+ self::append_style($cell, "; padding: {$value}px;");
308
+ }
309
+
310
+ return null;
311
+ }
312
+
313
+ static protected function _set_table_border($node, $value) {
314
+ $cell_list = self::get_cell_list($node);
315
+
316
+ foreach ($cell_list as $cell) {
317
+ $style = rtrim($cell->getAttribute(self::$_style_attr));
318
+ $style .= "; border-width: " . ($value > 0 ? 1 : 0) . "pt; border-style: inset;";
319
+ $style = ltrim($style, ";");
320
+ $cell->setAttribute(self::$_style_attr, $style);
321
+ }
322
+
323
+ $style = rtrim($node->getAttribute(self::$_style_attr), ";");
324
+ $style .= "; border-width: $value" . "px; ";
325
+ return ltrim($style, "; ");
326
+ }
327
+
328
+ static protected function _set_table_cellspacing($node, $value) {
329
+ $style = rtrim($node->getAttribute(self::$_style_attr), ";");
330
+
331
+ if ( $value == 0 )
332
+ $style .= "; border-collapse: collapse;";
333
+
334
+ else
335
+ $style .= "; border-spacing: {$value}px; border-collapse: separate;";
336
+
337
+ return ltrim($style, ";");
338
+ }
339
+
340
+ static protected function _set_table_rules($node, $value) {
341
+ $new_style = "; border-collapse: collapse;";
342
+ switch ($value) {
343
+ case "none":
344
+ $new_style .= "border-style: none;";
345
+ break;
346
+
347
+ case "groups":
348
+ // FIXME: unsupported
349
+ return;
350
+
351
+ case "rows":
352
+ $new_style .= "border-style: solid none solid none; border-width: 1px; ";
353
+ break;
354
+
355
+ case "cols":
356
+ $new_style .= "border-style: none solid none solid; border-width: 1px; ";
357
+ break;
358
+
359
+ case "all":
360
+ $new_style .= "border-style: solid; border-width: 1px; ";
361
+ break;
362
+
363
+ default:
364
+ // Invalid value
365
+ return null;
366
+ }
367
+
368
+ $cell_list = self::get_cell_list($node);
369
+
370
+ foreach ($cell_list as $cell) {
371
+ $style = $cell->getAttribute(self::$_style_attr);
372
+ $style .= $new_style;
373
+ $cell->setAttribute(self::$_style_attr, $style);
374
+ }
375
+
376
+ $style = rtrim($node->getAttribute(self::$_style_attr), ";");
377
+ $style .= "; border-collapse: collapse; ";
378
+
379
+ return ltrim($style, "; ");
380
+ }
381
+
382
+ static protected function _set_hr_size($node, $value) {
383
+ $style = rtrim($node->getAttribute(self::$_style_attr), ";");
384
+ $style .= "; border-width: ".max(0, $value-2)."; ";
385
+ return ltrim($style, "; ");
386
+ }
387
+
388
+ static protected function _set_hr_align($node, $value) {
389
+ $style = rtrim($node->getAttribute(self::$_style_attr),";");
390
+ $width = $node->getAttribute("width");
391
+ if ( $width == "" )
392
+ $width = "100%";
393
+
394
+ $remainder = 100 - (double)rtrim($width, "% ");
395
+
396
+ switch ($value) {
397
+ case "left":
398
+ $style .= "; margin-right: $remainder %;";
399
+ break;
400
+
401
+ case "right":
402
+ $style .= "; margin-left: $remainder %;";
403
+ break;
404
+
405
+ case "center":
406
+ $style .= "; margin-left: auto; margin-right: auto;";
407
+ break;
408
+
409
+ default:
410
+ return null;
411
+ }
412
+ return ltrim($style, "; ");
413
+ }
414
+
415
+ static protected function _set_table_row_align($node, $value) {
416
+ $cell_list = self::get_cell_list($node);
417
+
418
+ foreach ($cell_list as $cell) {
419
+ self::append_style($cell, "; text-align: $value;");
420
+ }
421
+
422
+ return null;
423
+ }
424
+
425
+ static protected function _set_table_row_valign($node, $value) {
426
+ $cell_list = self::get_cell_list($node);
427
+
428
+ foreach ($cell_list as $cell) {
429
+ self::append_style($cell, "; vertical-align: $value;");
430
+ }
431
+
432
+ return null;
433
+ }
434
+
435
+ static protected function _set_table_row_bgcolor($node, $value) {
436
+ $cell_list = self::get_cell_list($node);
437
+ $value = self::_get_valid_color($value);
438
+
439
+ foreach ($cell_list as $cell) {
440
+ self::append_style($cell, "; background-color: $value;");
441
+ }
442
+
443
+ return null;
444
+ }
445
+
446
+ static protected function _set_body_link($node, $value) {
447
+ $a_list = $node->getElementsByTagName("a");
448
+ $value = self::_get_valid_color($value);
449
+
450
+ foreach ($a_list as $a) {
451
+ self::append_style($a, "; color: $value;");
452
+ }
453
+
454
+ return null;
455
+ }
456
+
457
+ static protected function _set_basefont_size($node, $value) {
458
+ // FIXME: ? we don't actually set the font size of anything here, just
459
+ // the base size for later modification by <font> tags.
460
+ self::$_last_basefont_size = $value;
461
+ return null;
462
+ }
463
+
464
+ static protected function _set_font_size($node, $value) {
465
+ $style = $node->getAttribute(self::$_style_attr);
466
+
467
+ if ( $value[0] === "-" || $value[0] === "+" )
468
+ $value = self::$_last_basefont_size + (int)$value;
469
+
470
+ if ( isset(self::$_font_size_lookup[$value]) )
471
+ $style .= "; font-size: " . self::$_font_size_lookup[$value] . ";";
472
+ else
473
+ $style .= "; font-size: $value;";
474
+
475
+ return ltrim($style, "; ");
476
+ }
477
+ }
dompdf/include/autoload.inc.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: autoload.inc.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * DOMPDF autoload function
13
+ *
14
+ * If you have an existing autoload function, add a call to this function
15
+ * from your existing __autoload() implementation.
16
+ *
17
+ * @param string $class
18
+ */
19
+ function DOMPDF_autoload($class) {
20
+ $filename = DOMPDF_INC_DIR . "/" . mb_strtolower($class) . ".cls.php";
21
+
22
+ if ( is_file($filename) )
23
+ require_once($filename);
24
+ }
25
+
26
+ // If SPL autoload functions are available (PHP >= 5.1.2)
27
+ if ( function_exists("spl_autoload_register") ) {
28
+ $autoload = "DOMPDF_autoload";
29
+ $funcs = spl_autoload_functions();
30
+
31
+ // No functions currently in the stack.
32
+ if ( !DOMPDF_AUTOLOAD_PREPEND || $funcs === false ) {
33
+ spl_autoload_register($autoload);
34
+ }
35
+
36
+ // If PHP >= 5.3 the $prepend argument is available
37
+ else if ( PHP_VERSION_ID >= 50300 ) {
38
+ spl_autoload_register($autoload, true, true);
39
+ }
40
+
41
+ else {
42
+ // Unregister existing autoloaders...
43
+ $compat = (PHP_VERSION_ID <= 50102 && PHP_VERSION_ID >= 50100);
44
+
45
+ foreach ($funcs as $func) {
46
+ if (is_array($func)) {
47
+ // :TRICKY: There are some compatibility issues and some
48
+ // places where we need to error out
49
+ $reflector = new ReflectionMethod($func[0], $func[1]);
50
+ if (!$reflector->isStatic()) {
51
+ throw new Exception('This function is not compatible with non-static object methods due to PHP Bug #44144.');
52
+ }
53
+
54
+ // Suprisingly, spl_autoload_register supports the
55
+ // Class::staticMethod callback format, although call_user_func doesn't
56
+ if ($compat) $func = implode('::', $func);
57
+ }
58
+
59
+ spl_autoload_unregister($func);
60
+ }
61
+
62
+ // Register the new one, thus putting it at the front of the stack...
63
+ spl_autoload_register($autoload);
64
+
65
+ // Now, go back and re-register all of our old ones.
66
+ foreach ($funcs as $func) {
67
+ spl_autoload_register($func);
68
+ }
69
+
70
+ // Be polite and ensure that userland autoload gets retained
71
+ if ( function_exists("__autoload") ) {
72
+ spl_autoload_register("__autoload");
73
+ }
74
+ }
75
+ }
76
+
77
+ else if ( !function_exists("__autoload") ) {
78
+ /**
79
+ * Default __autoload() function
80
+ *
81
+ * @param string $class
82
+ */
83
+ function __autoload($class) {
84
+ DOMPDF_autoload($class);
85
+ }
86
+ }
dompdf/include/block_frame_decorator.cls.php ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: block_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Decorates frames for block layout
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Block_Frame_Decorator extends Frame_Decorator {
17
+ protected $_cl; // current line index
18
+
19
+ /**
20
+ * The block's line boxes
21
+ *
22
+ * @var array
23
+ */
24
+ protected $_line_boxes;
25
+
26
+ //........................................................................
27
+
28
+ function __construct(Frame $frame, DOMPDF $dompdf) {
29
+ parent::__construct($frame, $dompdf);
30
+
31
+ $this->_line_boxes = array(new Line_Box($this));
32
+ $this->_cl = 0;
33
+ }
34
+
35
+ //........................................................................
36
+
37
+ function reset() {
38
+ parent::reset();
39
+
40
+ $this->_line_boxes = array(new Line_Box($this));
41
+ $this->_cl = 0;
42
+ }
43
+
44
+ //........................................................................
45
+
46
+ // Accessor methods
47
+
48
+ /**
49
+ * @return Line_Box
50
+ */
51
+ function get_current_line_box() {
52
+ return $this->_line_boxes[$this->_cl];
53
+ }
54
+
55
+ /**
56
+ * @return integer
57
+ */
58
+ function get_current_line_number() {
59
+ return $this->_cl;
60
+ }
61
+
62
+ /**
63
+ * @return array
64
+ */
65
+ function get_line_boxes() {
66
+ return $this->_line_boxes;
67
+ }
68
+
69
+ //........................................................................
70
+
71
+ // Set methods
72
+ function set_current_line($y = null, $w = null, $h = null, $tallest_frame = null, $left = null, $right = null) {
73
+ $this->set_line($this->_cl, $y, $w, $h, $tallest_frame, $left, $right);
74
+ }
75
+
76
+ function clear_line($i) {
77
+ if ( isset($this->_line_boxes[$i]) )
78
+ unset($this->_line_boxes[$i]);
79
+ }
80
+
81
+ /**
82
+ * @todo change this this to better use the Line_Box object
83
+ * @param $lineno
84
+ * @param $y
85
+ * @param $w
86
+ * @param $h
87
+ * @param $tallest_frame
88
+ * @param $left
89
+ * @param $right
90
+ */
91
+ function set_line($lineno, $y = null, $w = null, $h = null, $tallest_frame = null, $left = null, $right = null) {
92
+
93
+ if ( is_array($y) )
94
+ extract($y);
95
+
96
+ if (is_numeric($y))
97
+ $this->_line_boxes[$lineno]->y = $y;
98
+
99
+ if (is_numeric($w))
100
+ $this->_line_boxes[$lineno]->w = $w;
101
+
102
+ if (is_numeric($h))
103
+ $this->_line_boxes[$lineno]->h = $h;
104
+
105
+ if ($tallest_frame && $tallest_frame instanceof Frame)
106
+ $this->_line_boxes[$lineno]->tallest_frame = $tallest_frame;
107
+
108
+ if (is_numeric($left))
109
+ $this->_line_boxes[$lineno]->left = $left;
110
+
111
+ if (is_numeric($right))
112
+ $this->_line_boxes[$lineno]->right = $right;
113
+ }
114
+
115
+
116
+ function add_frame_to_line(Frame $frame) {
117
+ if ( !$frame->is_in_flow() ) {
118
+ return;
119
+ }
120
+
121
+ $style = $frame->get_style();
122
+
123
+ $frame->set_containing_line($this->_line_boxes[$this->_cl]);
124
+
125
+ /*
126
+ // Adds a new line after a block, only if certain conditions are met
127
+ if ((($frame instanceof Inline_Frame_Decorator && $frame->get_node()->nodeName !== "br") ||
128
+ $frame instanceof Text_Frame_Decorator && trim($frame->get_text())) &&
129
+ ($frame->get_prev_sibling() && $frame->get_prev_sibling()->get_style()->display === "block" &&
130
+ $this->_line_boxes[$this->_cl]->w > 0 )) {
131
+
132
+ $this->maximize_line_height( $style->length_in_pt($style->line_height), $frame );
133
+ $this->add_line();
134
+
135
+ // Add each child of the inline frame to the line individually
136
+ foreach ($frame->get_children() as $child)
137
+ $this->add_frame_to_line( $child );
138
+ }
139
+ else*/
140
+
141
+ // Handle inline frames (which are effectively wrappers)
142
+ if ( $frame instanceof Inline_Frame_Decorator ) {
143
+
144
+ // Handle line breaks
145
+ if ( $frame->get_node()->nodeName === "br" ) {
146
+ $this->maximize_line_height( $style->length_in_pt($style->line_height), $frame );
147
+ $this->add_line(true);
148
+ }
149
+
150
+ return;
151
+ }
152
+
153
+ // Trim leading text if this is an empty line. Kinda a hack to put it here,
154
+ // but what can you do...
155
+ if ( $this->get_current_line_box()->w == 0 &&
156
+ $frame->is_text_node() &&
157
+ !$frame->is_pre() ) {
158
+
159
+ $frame->set_text( ltrim($frame->get_text()) );
160
+ $frame->recalculate_width();
161
+ }
162
+
163
+ $w = $frame->get_margin_width();
164
+
165
+ if ( $w == 0 )
166
+ return;
167
+
168
+ // Debugging code:
169
+ /*
170
+ pre_r("\n<h3>Adding frame to line:</h3>");
171
+
172
+ // pre_r("Me: " . $this->get_node()->nodeName . " (" . spl_object_hash($this->get_node()) . ")");
173
+ // pre_r("Node: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")");
174
+ if ( $frame->is_text_node() )
175
+ pre_r('"'.$frame->get_node()->nodeValue.'"');
176
+
177
+ pre_r("Line width: " . $this->_line_boxes[$this->_cl]->w);
178
+ pre_r("Frame: " . get_class($frame));
179
+ pre_r("Frame width: " . $w);
180
+ pre_r("Frame height: " . $frame->get_margin_height());
181
+ pre_r("Containing block width: " . $this->get_containing_block("w"));
182
+ */
183
+ // End debugging
184
+
185
+ $line = $this->_line_boxes[$this->_cl];
186
+ if ( $line->left + $line->w + $line->right + $w > $this->get_containing_block("w"))
187
+ $this->add_line();
188
+
189
+ $frame->position();
190
+
191
+ $current_line = $this->_line_boxes[$this->_cl];
192
+ $current_line->add_frame($frame);
193
+
194
+ if ( $frame->is_text_node() )
195
+ $current_line->wc += count(preg_split("/\s+/", trim($frame->get_text())));
196
+
197
+ $this->increase_line_width($w);
198
+
199
+ $this->maximize_line_height($frame->get_margin_height(), $frame);
200
+ }
201
+
202
+ function remove_frames_from_line(Frame $frame) {
203
+ // Search backwards through the lines for $frame
204
+ $i = $this->_cl;
205
+
206
+ while ($i >= 0) {
207
+ if ( ($j = in_array($frame, $this->_line_boxes[$i]->get_frames(), true)) !== false )
208
+ break;
209
+ $i--;
210
+ }
211
+
212
+ if ( $j === false )
213
+ return;
214
+
215
+ // Remove $frame and all frames that follow
216
+ while ($j < count($this->_line_boxes[$i]->get_frames())) {
217
+ $frames = $this->_line_boxes[$i]->get_frames();
218
+ $f = $frames[$j];
219
+ $frames[$j] = null;
220
+ unset($frames[$j]);
221
+ $j++;
222
+ $this->_line_boxes[$i]->w -= $f->get_margin_width();
223
+ }
224
+
225
+ // Recalculate the height of the line
226
+ $h = 0;
227
+ foreach ($this->_line_boxes[$i]->get_frames() as $f)
228
+ $h = max( $h, $f->get_margin_height() );
229
+
230
+ $this->_line_boxes[$i]->h = $h;
231
+
232
+ // Remove all lines that follow
233
+ while ($this->_cl > $i) {
234
+ $this->_line_boxes[ $this->_cl ] = null;
235
+ unset($this->_line_boxes[ $this->_cl ]);
236
+ $this->_cl--;
237
+ }
238
+ }
239
+
240
+ function increase_line_width($w) {
241
+ $this->_line_boxes[ $this->_cl ]->w += $w;
242
+ }
243
+
244
+ function maximize_line_height($val, Frame $frame) {
245
+ if ( $val > $this->_line_boxes[ $this->_cl ]->h ) {
246
+ $this->_line_boxes[ $this->_cl ]->tallest_frame = $frame;
247
+ $this->_line_boxes[ $this->_cl ]->h = $val;
248
+ }
249
+ }
250
+
251
+ function add_line($br = false) {
252
+
253
+ // if ( $this->_line_boxes[$this->_cl]["h"] == 0 ) //count($this->_line_boxes[$i]["frames"]) == 0 ||
254
+ // return;
255
+
256
+ $this->_line_boxes[$this->_cl]->br = $br;
257
+ $y = $this->_line_boxes[$this->_cl]->y + $this->_line_boxes[$this->_cl]->h;
258
+
259
+ $new_line = new Line_Box($this, $y);
260
+
261
+ $this->_line_boxes[ ++$this->_cl ] = $new_line;
262
+ }
263
+
264
+ //........................................................................
265
+ }
dompdf/include/block_frame_reflower.cls.php ADDED
@@ -0,0 +1,776 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: block_frame_reflower.cls.php 471 2012-02-06 21:59:10Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Reflows block frames
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Block_Frame_Reflower extends Frame_Reflower {
18
+ // Minimum line width to justify, as fraction of available width
19
+ const MIN_JUSTIFY_WIDTH = 0.80;
20
+
21
+ /**
22
+ * @var Block_Frame_Decorator
23
+ */
24
+ protected $_frame;
25
+
26
+ function __construct(Block_Frame_Decorator $frame) { parent::__construct($frame); }
27
+
28
+ /**
29
+ * Calculate the ideal used value for the width property as per:
30
+ * http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins
31
+ *
32
+ * @param float $width
33
+ * @return array
34
+ */
35
+ protected function _calculate_width($width) {
36
+ $frame = $this->_frame;
37
+ $style = $frame->get_style();
38
+ $w = $frame->get_containing_block("w");
39
+
40
+ if ( $style->position === "fixed" ) {
41
+ $w = $frame->get_parent()->get_containing_block("w");
42
+ }
43
+
44
+ $rm = $style->length_in_pt($style->margin_right, $w);
45
+ $lm = $style->length_in_pt($style->margin_left, $w);
46
+
47
+ $left = $style->length_in_pt($style->left, $w);
48
+ $right = $style->length_in_pt($style->right, $w);
49
+
50
+ // Handle 'auto' values
51
+ $dims = array($style->border_left_width,
52
+ $style->border_right_width,
53
+ $style->padding_left,
54
+ $style->padding_right,
55
+ $width !== "auto" ? $width : 0,
56
+ $rm !== "auto" ? $rm : 0,
57
+ $lm !== "auto" ? $lm : 0);
58
+
59
+ // absolutely positioned boxes take the 'left' and 'right' properties into account
60
+ if ( $frame->is_absolute() ) {
61
+ $absolute = true;
62
+ $dims[] = $left !== "auto" ? $left : 0;
63
+ $dims[] = $right !== "auto" ? $right : 0;
64
+ } else {
65
+ $absolute = false;
66
+ }
67
+
68
+ $sum = $style->length_in_pt($dims, $w);
69
+
70
+ // Compare to the containing block
71
+ $diff = $w - $sum;
72
+
73
+ if ( $diff > 0 ) {
74
+
75
+ if ( $absolute ) {
76
+
77
+ // resolve auto properties: see
78
+ // http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
79
+
80
+ if ( $width === "auto" && $left === "auto" && $right === "auto" ) {
81
+
82
+ if ( $lm === "auto" )
83
+ $lm = 0;
84
+ if ( $rm === "auto" )
85
+ $rm = 0;
86
+
87
+ // Technically, the width should be "shrink-to-fit" i.e. based on the
88
+ // preferred width of the content... a little too costly here as a
89
+ // special case. Just get the width to take up the slack:
90
+ $left = 0;
91
+ $right = 0;
92
+ $width = $diff;
93
+
94
+ } else if ( $width === "auto" ) {
95
+
96
+ if ( $lm === "auto" )
97
+ $lm = 0;
98
+ if ( $rm === "auto" )
99
+ $rm = 0;
100
+ if ( $left === "auto" )
101
+ $left = 0;
102
+ if ( $right === "auto" )
103
+ $right = 0;
104
+
105
+ $width = $diff;
106
+
107
+ } else if ( $left === "auto" ) {
108
+
109
+ if ( $lm === "auto" )
110
+ $lm = 0;
111
+ if ( $rm === "auto" )
112
+ $rm = 0;
113
+ if ( $right === "auto" )
114
+ $right = 0;
115
+
116
+ $left = $diff;
117
+
118
+ } else if ( $right === "auto" ) {
119
+
120
+ if ( $lm === "auto" )
121
+ $lm = 0;
122
+ if ( $rm === "auto" )
123
+ $rm = 0;
124
+
125
+ $right = $diff;
126
+ }
127
+
128
+ } else {
129
+
130
+ // Find auto properties and get them to take up the slack
131
+ if ( $width === "auto" )
132
+ $width = $diff;
133
+
134
+ else if ( $lm === "auto" && $rm === "auto" )
135
+ $lm = $rm = round($diff / 2);
136
+
137
+ else if ( $lm === "auto" )
138
+ $lm = $diff;
139
+
140
+ else if ( $rm === "auto" )
141
+ $rm = $diff;
142
+ }
143
+
144
+ } else if ($diff < 0) {
145
+
146
+ // We are over constrained--set margin-right to the difference
147
+ $rm = $diff;
148
+
149
+ }
150
+
151
+ return array("width"=> $width, "margin_left" => $lm, "margin_right" => $rm, "left" => $left, "right" => $right);
152
+ }
153
+
154
+ /**
155
+ * Call the above function, but resolve max/min widths
156
+ * @return array
157
+ */
158
+ protected function _calculate_restricted_width() {
159
+ $frame = $this->_frame;
160
+ $style = $frame->get_style();
161
+ $cb = $frame->get_containing_block();
162
+
163
+ if ( $style->position === "fixed" ) {
164
+ $cb = $frame->get_root()->get_containing_block();
165
+ }
166
+
167
+ //if ( $style->position === "absolute" )
168
+ // $cb = $frame->find_positionned_parent()->get_containing_block();
169
+
170
+ if ( !isset($cb["w"]) )
171
+ throw new DOMPDF_Exception("Box property calculation requires containing block width");
172
+
173
+ // Treat width 100% as auto
174
+ if ( $style->width === "100%" ) {
175
+ $width = "auto";
176
+ }
177
+ else {
178
+ $width = $style->length_in_pt($style->width, $cb["w"]);
179
+ }
180
+ extract($this->_calculate_width($width));
181
+
182
+ // Handle min/max width
183
+ $min_width = $style->length_in_pt($style->min_width, $cb["w"]);
184
+ $max_width = $style->length_in_pt($style->max_width, $cb["w"]);
185
+
186
+ if ( $max_width !== "none" && $min_width > $max_width)
187
+ // Swap 'em
188
+ list($max_width, $min_width) = array($min_width, $max_width);
189
+
190
+ if ( $max_width !== "none" && $width > $max_width )
191
+ extract($this->_calculate_width($max_width));
192
+
193
+ if ( $width < $min_width )
194
+ extract($this->_calculate_width($min_width));
195
+
196
+ return array($width, $margin_left, $margin_right, $left, $right);
197
+
198
+ }
199
+
200
+ /**
201
+ * Determine the unrestricted height of content within the block
202
+ * not by adding each line's height, but by getting the last line's position.
203
+ * This because lines could have been pushed lower by a clearing element.
204
+ * @return float
205
+ */
206
+ protected function _calculate_content_height() {
207
+ $lines = $this->_frame->get_line_boxes();
208
+
209
+ $first_line = reset($lines);
210
+ $last_line = end($lines);
211
+ $height = $last_line->y + $last_line->h - $first_line->y;
212
+
213
+ return $height;
214
+ }
215
+
216
+ /**
217
+ * Determine the frame's restricted height
218
+ * @return array
219
+ */
220
+ protected function _calculate_restricted_height() {
221
+ $frame = $this->_frame;
222
+ $style = $frame->get_style();
223
+ $content_height = $this->_calculate_content_height();
224
+ $cb = $frame->get_containing_block();
225
+
226
+ $height = $style->length_in_pt($style->height, $cb["h"]);
227
+
228
+ $top = $style->length_in_pt($style->top, $cb["h"]);
229
+ $bottom = $style->length_in_pt($style->bottom, $cb["h"]);
230
+
231
+ $margin_top = $style->length_in_pt($style->margin_top, $cb["h"]);
232
+ $margin_bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]);
233
+
234
+ if ( $frame->is_absolute() ) {
235
+
236
+ // see http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
237
+
238
+ $dims = array($top !== "auto" ? $top : 0,
239
+ $style->margin_top !== "auto" ? $style->margin_top : 0,
240
+ $style->padding_top,
241
+ $style->border_top_width,
242
+ $height !== "auto" ? $height : 0,
243
+ $style->border_bottom_width,
244
+ $style->padding_bottom,
245
+ $style->margin_bottom !== "auto" ? $style->margin_bottom : 0,
246
+ $bottom !== "auto" ? $bottom : 0);
247
+
248
+ $sum = $style->length_in_pt($dims, $cb["h"]);
249
+
250
+ $diff = $cb["h"] - $sum;
251
+
252
+ if ( $diff > 0 ) {
253
+
254
+ if ( $height === "auto" && $top === "auto" && $bottom === "auto" ) {
255
+
256
+ if ( $margin_top === "auto" )
257
+ $margin_top = 0;
258
+ if ( $margin_bottom === "auto" )
259
+ $margin_bottom = 0;
260
+
261
+ $height = $diff;
262
+
263
+ } else if ( $height === "auto" && $top === "auto" ) {
264
+
265
+ if ( $margin_top === "auto" )
266
+ $margin_top = 0;
267
+ if ( $margin_bottom === "auto" )
268
+ $margin_bottom = 0;
269
+
270
+ $height = $content_height;
271
+ $top = $diff - $content_height;
272
+
273
+ } else if ( $height === "auto" && $bottom === "auto" ) {
274
+
275
+ if ( $margin_top === "auto" )
276
+ $margin_top = 0;
277
+ if ( $margin_bottom === "auto" )
278
+ $margin_bottom = 0;
279
+
280
+ $height = $content_height;
281
+ $bottom = $diff - $content_height;
282
+
283
+ } else if ( $top === "auto" && $bottom === "auto" ) {
284
+
285
+ if ( $margin_top === "auto" )
286
+ $margin_top = 0;
287
+ if ( $margin_bottom === "auto" )
288
+ $margin_bottom = 0;
289
+
290
+ $bottom = $diff;
291
+
292
+ } else if ( $top === "auto" ) {
293
+
294
+ if ( $margin_top === "auto" )
295
+ $margin_top = 0;
296
+ if ( $margin_bottom === "auto" )
297
+ $margin_bottom = 0;
298
+
299
+ $top = $diff;
300
+
301
+ } else if ( $height === "auto" ) {
302
+
303
+ if ( $margin_top === "auto" )
304
+ $margin_top = 0;
305
+ if ( $margin_bottom === "auto" )
306
+ $margin_bottom = 0;
307
+
308
+ $height = $diff;
309
+
310
+ } else if ( $bottom === "auto" ) {
311
+
312
+ if ( $margin_top === "auto" )
313
+ $margin_top = 0;
314
+ if ( $margin_bottom === "auto" )
315
+ $margin_bottom = 0;
316
+
317
+ $bottom = $diff;
318
+
319
+ } else {
320
+
321
+ if ( $style->overflow === "visible" ) {
322
+
323
+ // set all autos to zero
324
+ if ( $margin_top === "auto" )
325
+ $margin_top = 0;
326
+ if ( $margin_bottom === "auto" )
327
+ $margin_bottom = 0;
328
+ if ( $top === "auto" )
329
+ $top = 0;
330
+ if ( $bottom === "auto" )
331
+ $bottom = 0;
332
+ if ( $height === "auto" )
333
+ $height = $content_height;
334
+
335
+ }
336
+
337
+ // FIXME: overflow hidden
338
+ }
339
+
340
+ }
341
+
342
+ } else {
343
+
344
+ // Expand the height if overflow is visible
345
+ if ( $height === "auto" && $content_height > $height /* && $style->overflow === "visible" */)
346
+ $height = $content_height;
347
+
348
+ // FIXME: this should probably be moved to a seperate function as per
349
+ // _calculate_restricted_width
350
+
351
+ // Only handle min/max height if the height is independent of the frame's content
352
+ if ( !($style->overflow === "visible" ||
353
+ ($style->overflow === "hidden" && $height === "auto")) ) {
354
+
355
+ $min_height = $style->min_height;
356
+ $max_height = $style->max_height;
357
+
358
+ if ( isset($cb["h"]) ) {
359
+ $min_height = $style->length_in_pt($min_height, $cb["h"]);
360
+ $max_height = $style->length_in_pt($max_height, $cb["h"]);
361
+
362
+ } else if ( isset($cb["w"]) ) {
363
+
364
+ if ( mb_strpos($min_height, "%") !== false )
365
+ $min_height = 0;
366
+ else
367
+ $min_height = $style->length_in_pt($min_height, $cb["w"]);
368
+
369
+ if ( mb_strpos($max_height, "%") !== false )
370
+ $max_height = "none";
371
+ else
372
+ $max_height = $style->length_in_pt($max_height, $cb["w"]);
373
+ }
374
+
375
+ if ( $max_height !== "none" && $min_height > $max_height )
376
+ // Swap 'em
377
+ list($max_height, $min_height) = array($min_height, $max_height);
378
+
379
+ if ( $max_height !== "none" && $height > $max_height )
380
+ $height = $max_height;
381
+
382
+ if ( $height < $min_height )
383
+ $height = $min_height;
384
+ }
385
+
386
+ }
387
+
388
+ return array($height, $margin_top, $margin_bottom, $top, $bottom);
389
+
390
+ }
391
+
392
+ /**
393
+ * Adjust the justification of each of our lines.
394
+ * http://www.w3.org/TR/CSS21/text.html#propdef-text-align
395
+ */
396
+ protected function _text_align() {
397
+ $style = $this->_frame->get_style();
398
+ $w = $this->_frame->get_containing_block("w");
399
+ $width = $style->length_in_pt($style->width, $w);
400
+ switch ($style->text_align) {
401
+
402
+ default:
403
+ case "left":
404
+ foreach ($this->_frame->get_line_boxes() as $line) {
405
+ if ( !$line->left ) continue;
406
+ foreach($line->get_frames() as $frame) {
407
+ if ( $frame instanceof Block_Frame_Decorator) continue;
408
+ $frame->set_position( $frame->get_position("x") + $line->left );
409
+ }
410
+ }
411
+ return;
412
+
413
+ case "right":
414
+ foreach ($this->_frame->get_line_boxes() as $line) {
415
+ // Move each child over by $dx
416
+ $dx = $width - $line->w - $line->right;
417
+
418
+ foreach($line->get_frames() as $frame) {
419
+ // Block frames are not aligned by text-align
420
+ if ($frame instanceof Block_Frame_Decorator) continue;
421
+
422
+ $frame->set_position( $frame->get_position("x") + $dx );
423
+ }
424
+ }
425
+ break;
426
+
427
+
428
+ case "justify":
429
+ // We justify all lines except the last one
430
+ $lines = $this->_frame->get_line_boxes(); // needs to be a variable (strict standards)
431
+ $lines = array_splice($lines, 0, -1);
432
+
433
+ foreach($lines as $i => $line) {
434
+ if ( $line->br ) {
435
+ unset($lines[$i]);
436
+ }
437
+ }
438
+
439
+ // One space character's width. Will be used to get a more accurate spacing
440
+ $space_width = Font_Metrics::get_text_width(" ", $style->font_family, $style->font_size);
441
+
442
+ foreach ($lines as $i => $line) {
443
+ if ( $line->left ) {
444
+ foreach($line->get_frames() as $frame) {
445
+ if ( !$frame instanceof Text_Frame_Decorator )
446
+ continue;
447
+
448
+ $frame->set_position( $frame->get_position("x") + $line->left );
449
+ }
450
+ }
451
+
452
+ // Only set the spacing if the line is long enough. This is really
453
+ // just an aesthetic choice ;)
454
+ //if ( $line["left"] + $line["w"] + $line["right"] > self::MIN_JUSTIFY_WIDTH * $width ) {
455
+
456
+ // Set the spacing for each child
457
+ if ( $line->wc > 1 )
458
+ $spacing = ($width - ($line->left + $line->w + $line->right) + $space_width) / ($line->wc - 1);
459
+ else
460
+ $spacing = 0;
461
+
462
+ $dx = 0;
463
+ foreach($line->get_frames() as $frame) {
464
+ if ( !$frame instanceof Text_Frame_Decorator )
465
+ continue;
466
+
467
+ $text = $frame->get_text();
468
+ $spaces = mb_substr_count($text, " ");
469
+
470
+ $char_spacing = $style->length_in_pt($style->letter_spacing);
471
+ $_spacing = $spacing + $char_spacing;
472
+
473
+ $frame->set_position( $frame->get_position("x") + $dx );
474
+ $frame->set_text_spacing($_spacing);
475
+
476
+ $dx += $spaces * $_spacing;
477
+ }
478
+
479
+ // The line (should) now occupy the entire width
480
+ $this->_frame->set_line($i, null, $width);
481
+
482
+ //}
483
+ }
484
+ break;
485
+
486
+ case "center":
487
+ case "centre":
488
+ foreach ($this->_frame->get_line_boxes() as $line) {
489
+ // Centre each line by moving each frame in the line by:
490
+ $dx = ($width + $line->left - $line->w - $line->right ) / 2;
491
+
492
+ foreach ($line->get_frames() as $frame) {
493
+ // Block frames are not aligned by text-align
494
+ if ($frame instanceof Block_Frame_Decorator) continue;
495
+
496
+ $frame->set_position( $frame->get_position("x") + $dx );
497
+ }
498
+ }
499
+ break;
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Align inline children vertically.
505
+ * Aligns each child vertically after each line is reflowed
506
+ */
507
+ function vertical_align() {
508
+
509
+ $canvas = null;
510
+
511
+ foreach ( $this->_frame->get_line_boxes() as $line ) {
512
+
513
+ $height = $line->h;
514
+
515
+ foreach ( $line->get_frames() as $frame ) {
516
+ $style = $frame->get_style();
517
+
518
+ if ( $style->display !== "inline" && $style->display !== "text" )
519
+ continue;
520
+
521
+ // FIXME?
522
+ if ( $this instanceof Table_Cell_Frame_Reflower )
523
+ $align = $frame->get_frame()->get_style()->vertical_align;
524
+ else
525
+ $align = $frame->get_frame()->get_parent()->get_style()->vertical_align;
526
+
527
+ $frame_h = $frame->get_margin_height();
528
+
529
+ if ( !isset($canvas) ) {
530
+ $canvas = $frame->get_root()->get_dompdf()->get_canvas();
531
+ }
532
+
533
+ $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size);
534
+ $y_offset = 0;
535
+
536
+ switch ($align) {
537
+ case "baseline":
538
+ $y_offset = $height*0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning
539
+ break;
540
+
541
+ case "middle":
542
+ $y_offset = ($height*0.8 - $baseline) / 2;
543
+ break;
544
+
545
+ case "sub":
546
+ $y_offset = 0.3 * $height;
547
+ break;
548
+
549
+ case "super":
550
+ $y_offset = -0.2 * $height;
551
+ break;
552
+
553
+ case "text-top":
554
+ case "top": // Not strictly accurate, but good enough for now
555
+ break;
556
+
557
+ case "text-bottom":
558
+ case "bottom":
559
+ $y_offset = $height*0.8 - $baseline;
560
+ break;
561
+ }
562
+
563
+ if ( $y_offset ) {
564
+ $frame->move(0, $y_offset);
565
+ }
566
+ }
567
+ }
568
+ }
569
+
570
+ function process_clear(Frame $child){
571
+ if ( !DOMPDF_ENABLE_CSS_FLOAT ) {
572
+ return;
573
+ }
574
+
575
+ $child_style = $child->get_style();
576
+ $root = $this->_frame->get_root();
577
+
578
+ // Handle "clear"
579
+ if ( $child_style->clear !== "none" ) {
580
+ $lowest_y = $root->get_lowest_float_offset($child);
581
+
582
+ // If a float is still applying, we handle it
583
+ if ( $lowest_y ) {
584
+ if ( $child->is_in_flow() ) {
585
+ $line_box = $this->_frame->get_current_line_box();
586
+ $line_box->y = $lowest_y + $child->get_margin_height();
587
+ $line_box->left = 0;
588
+ $line_box->right = 0;
589
+ }
590
+
591
+ $child->move(0, $lowest_y - $child->get_position("y"));
592
+ }
593
+ }
594
+ }
595
+
596
+ function process_float(Frame $child, $cb_x, $cb_w){
597
+ if ( !DOMPDF_ENABLE_CSS_FLOAT ) {
598
+ return;
599
+ }
600
+
601
+ $child_style = $child->get_style();
602
+ $root = $this->_frame->get_root();
603
+
604
+ // Handle "float"
605
+ if ( $child_style->float !== "none" ) {
606
+ $root->add_floating_frame($child);
607
+
608
+ // Remove next frame's beginning whitespace
609
+ $next = $child->get_next_sibling();
610
+ if ( $next && $next instanceof Text_Frame_Decorator) {
611
+ $next->set_text(ltrim($next->get_text()));
612
+ }
613
+
614
+ $line_box = $this->_frame->get_current_line_box();
615
+ list($old_x, $old_y) = $child->get_position();
616
+
617
+ $float_x = $cb_x;
618
+ $float_y = $old_y;
619
+ $float_w = $child->get_margin_width();
620
+
621
+ if ( $child_style->clear === "none" ) {
622
+ switch( $child_style->float ) {
623
+ case "left":
624
+ $float_x += $line_box->left;
625
+ break;
626
+ case "right":
627
+ $float_x += ($cb_w - $line_box->right - $float_w);
628
+ break;
629
+ }
630
+ }
631
+ else {
632
+ if ( $child_style->float === "right" ) {
633
+ $float_x += ($cb_w - $float_w);
634
+ }
635
+ }
636
+
637
+ $line_box->get_float_offsets();
638
+
639
+ if ( $child->_float_next_line ) {
640
+ $float_y += $line_box->h;
641
+ }
642
+
643
+ $child->set_position($float_x, $float_y);
644
+ $child->move($float_x - $old_x, $float_y - $old_y, true);
645
+ }
646
+ }
647
+
648
+ function reflow(Frame_Decorator $block = null) {
649
+
650
+ // Check if a page break is forced
651
+ $page = $this->_frame->get_root();
652
+ $page->check_forced_page_break($this->_frame);
653
+
654
+ // Bail if the page is full
655
+ if ( $page->is_full() )
656
+ return;
657
+
658
+ // Generated content
659
+ $this->_set_content();
660
+
661
+ // Collapse margins if required
662
+ $this->_collapse_margins();
663
+
664
+ $style = $this->_frame->get_style();
665
+ $cb = $this->_frame->get_containing_block();
666
+
667
+ if ( $style->position === "fixed" ) {
668
+ $cb = $this->_frame->get_root()->get_containing_block();
669
+ }
670
+
671
+ // Determine the constraints imposed by this frame: calculate the width
672
+ // of the content area:
673
+ list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width();
674
+
675
+ // Store the calculated properties
676
+ $style->width = $w . "pt";
677
+ $style->margin_left = $left_margin."pt";
678
+ $style->margin_right = $right_margin."pt";
679
+ $style->left = $left ."pt";
680
+ $style->right = $right . "pt";
681
+
682
+ // Update the position
683
+ $this->_frame->position();
684
+ list($x, $y) = $this->_frame->get_position();
685
+
686
+ // Adjust the first line based on the text-indent property
687
+ $indent = $style->length_in_pt($style->text_indent, $cb["w"]);
688
+ $this->_frame->increase_line_width($indent);
689
+
690
+ // Determine the content edge
691
+ $top = $style->length_in_pt(array($style->margin_top,
692
+ $style->padding_top,
693
+ $style->border_top_width), $cb["h"]);
694
+
695
+ $bottom = $style->length_in_pt(array($style->border_bottom_width,
696
+ $style->margin_bottom,
697
+ $style->padding_bottom), $cb["h"]);
698
+
699
+ $cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width,
700
+ $style->padding_left), $cb["w"]);
701
+
702
+ $cb_y = $y + $top;
703
+
704
+ $cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y;
705
+
706
+ // Set the y position of the first line in this block
707
+ $this->_frame->set_current_line($cb_y);
708
+
709
+ $this->_frame->get_current_line_box()->get_float_offsets();
710
+
711
+ // Set the containing blocks and reflow each child
712
+ foreach ( $this->_frame->get_children() as $child ) {
713
+
714
+ // Bail out if the page is full
715
+ if ( $page->is_full() )
716
+ break;
717
+
718
+ $child->set_containing_block($cb_x, $cb_y, $w, $cb_h);
719
+
720
+ $this->process_clear($child);
721
+
722
+ $child->reflow($this->_frame);
723
+
724
+ // Don't add the child to the line if a page break has occurred
725
+ if ( $page->check_page_break($child) )
726
+ break;
727
+
728
+ $this->process_float($child, $cb_x, $w);
729
+ }
730
+
731
+ // Determine our height
732
+ list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height();
733
+ $style->height = $height;
734
+ $style->margin_top = $margin_top;
735
+ $style->margin_bottom = $margin_bottom;
736
+ $style->top = $top;
737
+ $style->bottom = $bottom;
738
+
739
+ $needs_reposition = ($style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto"));
740
+
741
+ // Absolute positioning measurement
742
+ if ( $needs_reposition ) {
743
+ $orig_style = $this->_frame->get_original_style();
744
+ if ( $orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto") ) {
745
+ $width = 0;
746
+ foreach ($this->_frame->get_line_boxes() as $line) {
747
+ $width = max($line->w, $width);
748
+ }
749
+ $style->width = $width;
750
+ }
751
+
752
+ $style->left = $orig_style->left;
753
+ $style->right = $orig_style->right;
754
+ }
755
+
756
+ $this->_text_align();
757
+ $this->vertical_align();
758
+
759
+ // Absolute positioning
760
+ if ( $needs_reposition ) {
761
+ list($x, $y) = $this->_frame->get_position();
762
+ $this->_frame->position();
763
+ list($new_x, $new_y) = $this->_frame->get_position();
764
+ $this->_frame->move($new_x-$x, $new_y-$y, true);
765
+ }
766
+
767
+ if ( $block && $this->_frame->is_in_flow() ) {
768
+ $block->add_frame_to_line($this->_frame);
769
+
770
+ // May be inline-block
771
+ if ( $style->display === "block" ) {
772
+ $block->add_line();
773
+ }
774
+ }
775
+ }
776
+ }
dompdf/include/block_positioner.cls.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: block_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Positions block frames
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Block_Positioner extends Positioner {
17
+
18
+
19
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
20
+
21
+ //........................................................................
22
+
23
+ function position() {
24
+ $frame = $this->_frame;
25
+ $style = $frame->get_style();
26
+ $cb = $frame->get_containing_block();
27
+ $p = $frame->find_block_parent();
28
+
29
+ if ( $p ) {
30
+ $float = $style->float;
31
+ if ( !DOMPDF_ENABLE_CSS_FLOAT || !$float || $float === "none" ) {
32
+ $p->add_line(true);
33
+ }
34
+ $y = $p->get_current_line_box()->y;
35
+
36
+ } else
37
+ $y = $cb["y"];
38
+
39
+ $x = $cb["x"];
40
+
41
+ // Relative positionning
42
+ if ( $style->position === "relative" ) {
43
+ $top = $style->length_in_pt($style->top, $cb["h"]);
44
+ //$right = $style->length_in_pt($style->right, $cb["w"]);
45
+ //$bottom = $style->length_in_pt($style->bottom, $cb["h"]);
46
+ $left = $style->length_in_pt($style->left, $cb["w"]);
47
+
48
+ $x += $left;
49
+ $y += $top;
50
+ }
51
+
52
+ $frame->set_position($x, $y);
53
+ }
54
+ }
dompdf/include/block_renderer.cls.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: block_renderer.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Renders block frames
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Block_Renderer extends Abstract_Renderer {
17
+
18
+ //........................................................................
19
+
20
+ function render(Frame $frame) {
21
+ $style = $frame->get_style();
22
+ list($x, $y, $w, $h) = $frame->get_border_box();
23
+
24
+ $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
25
+
26
+ if ( $frame->get_node()->nodeName === "body" ) {
27
+ $h = $frame->get_containing_block("h") - $style->length_in_pt(array(
28
+ $style->margin_top,
29
+ $style->padding_top,
30
+ $style->border_top_width,
31
+ $style->border_bottom_width,
32
+ $style->padding_bottom,
33
+ $style->margin_bottom),
34
+ $style->width);
35
+ }
36
+
37
+ // Draw our background, border and content
38
+ if ( ($bg = $style->background_color) !== "transparent" ) {
39
+ $this->_canvas->filled_rectangle( $x, $y, $w, $h, $bg );
40
+ }
41
+
42
+ if ( ($url = $style->background_image) && $url !== "none" )
43
+ $this->_background_image($url, $x, $y, $w, $h, $style);
44
+
45
+ $this->_render_border($frame);
46
+ $this->_render_outline($frame);
47
+
48
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) {
49
+ $this->_debug_layout($frame->get_border_box(), "red");
50
+ if (DEBUG_LAYOUT_PADDINGBOX) {
51
+ $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5));
52
+ }
53
+ }
54
+
55
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES && $frame->get_decorator()) {
56
+ foreach ($frame->get_decorator()->get_line_boxes() as $line) {
57
+ $frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange");
58
+ }
59
+ }
60
+ }
61
+
62
+ protected function _render_border(Frame_Decorator $frame, $corner_style = "bevel") {
63
+ $style = $frame->get_style();
64
+ $bbox = $frame->get_border_box();
65
+ $bp = $style->get_border_properties();
66
+
67
+ // If all the borders are "solid" with the same color and style, we'd better draw a rectangle
68
+ if (
69
+ in_array($bp["top"]["style"], array("solid", "dashed", "dotted")) &&
70
+ $bp["top"] == $bp["right"] &&
71
+ $bp["right"] == $bp["bottom"] &&
72
+ $bp["bottom"] == $bp["left"]
73
+ ) {
74
+ $props = $bp["top"];
75
+ if ( $props["color"] === "transparent" || $props["width"] <= 0 ) return;
76
+
77
+ list($x, $y, $w, $h) = $bbox;
78
+ $width = $style->length_in_pt($props["width"]);
79
+ $pattern = $this->_get_dash_pattern($props["style"], $width);
80
+ $this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width, $pattern);
81
+ return;
82
+ }
83
+
84
+ $widths = array($style->length_in_pt($bp["top"]["width"]),
85
+ $style->length_in_pt($bp["right"]["width"]),
86
+ $style->length_in_pt($bp["bottom"]["width"]),
87
+ $style->length_in_pt($bp["left"]["width"]));
88
+
89
+ foreach ($bp as $side => $props) {
90
+ list($x, $y, $w, $h) = $bbox;
91
+
92
+ if ( !$props["style"] ||
93
+ $props["style"] === "none" ||
94
+ $props["width"] <= 0 ||
95
+ $props["color"] == "transparent" )
96
+ continue;
97
+
98
+ switch($side) {
99
+ case "top":
100
+ $length = $w;
101
+ break;
102
+
103
+ case "bottom":
104
+ $length = $w;
105
+ $y += $h;
106
+ break;
107
+
108
+ case "left":
109
+ $length = $h;
110
+ break;
111
+
112
+ case "right":
113
+ $length = $h;
114
+ $x += $w;
115
+ break;
116
+ default:
117
+ break;
118
+ }
119
+ $method = "_border_" . $props["style"];
120
+
121
+ $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style);
122
+ }
123
+ }
124
+
125
+ protected function _render_outline(Frame_Decorator $frame, $corner_style = "bevel") {
126
+ $style = $frame->get_style();
127
+
128
+ $props = array(
129
+ "width" => $style->outline_width,
130
+ "style" => $style->outline_style,
131
+ "color" => $style->outline_color,
132
+ );
133
+
134
+ if ( !$props["style"] || $props["style"] === "none" || $props["width"] <= 0 )
135
+ return;
136
+
137
+ $bbox = $frame->get_border_box();
138
+ $offset = $style->length_in_pt($props["width"]);
139
+ $pattern = $this->_get_dash_pattern($props["style"], $offset);
140
+
141
+ // If the outline style is "solid" we'd better draw a rectangle
142
+ if ( in_array($props["style"], array("solid", "dashed", "dotted")) ) {
143
+ $bbox[0] -= $offset / 2;
144
+ $bbox[1] -= $offset / 2;
145
+ $bbox[2] += $offset;
146
+ $bbox[3] += $offset;
147
+
148
+ list($x, $y, $w, $h) = $bbox;
149
+ $this->_canvas->rectangle($x, $y, $w, $h, $props["color"], $offset, $pattern);
150
+ return;
151
+ }
152
+
153
+ $bbox[0] -= $offset;
154
+ $bbox[1] -= $offset;
155
+ $bbox[2] += $offset * 2;
156
+ $bbox[3] += $offset * 2;
157
+
158
+ $method = "_border_" . $props["style"];
159
+ $widths = array_fill(0, 4, $props["width"]);
160
+ $sides = array("top", "right", "left", "bottom");
161
+
162
+ foreach ($sides as $side) {
163
+ list($x, $y, $w, $h) = $bbox;
164
+
165
+ switch($side) {
166
+ case "top":
167
+ $length = $w;
168
+ break;
169
+
170
+ case "bottom":
171
+ $length = $w;
172
+ $y += $h;
173
+ break;
174
+
175
+ case "left":
176
+ $length = $h;
177
+ break;
178
+
179
+ case "right":
180
+ $length = $h;
181
+ $x += $w;
182
+ break;
183
+ default:
184
+ break;
185
+ }
186
+
187
+ $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style);
188
+ }
189
+ }
190
+ }
dompdf/include/cached_pdf_decorator.cls.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: cached_pdf_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Caching canvas implementation
12
+ *
13
+ * Each rendered page is serialized and stored in the {@link Page_Cache}.
14
+ * This is useful for static forms/pages that do not need to be re-rendered
15
+ * all the time.
16
+ *
17
+ * This class decorates normal CPDF_Adapters. It is currently completely
18
+ * experimental.
19
+ *
20
+ * @access private
21
+ * @package dompdf
22
+ */
23
+ class Cached_PDF_Decorator extends CPDF_Adapter implements Canvas {
24
+ protected $_pdf;
25
+ protected $_cache_id;
26
+ protected $_current_page_id;
27
+ protected $_fonts; // fonts used in this document
28
+
29
+ function __construct($cache_id, CPDF_Adapter $pdf) {
30
+ $this->_pdf = $pdf;
31
+ $this->_cache_id = $cache_id;
32
+ $this->_fonts = array();
33
+
34
+ $this->_current_page_id = $this->_pdf->open_object();
35
+ }
36
+
37
+ //........................................................................
38
+
39
+ function get_cpdf() { return $this->_pdf->get_cpdf(); }
40
+
41
+ function open_object() { $this->_pdf->open_object(); }
42
+ function reopen_object() { return $this->_pdf->reopen_object(); }
43
+
44
+ function close_object() { $this->_pdf->close_object(); }
45
+
46
+ function add_object($object, $where = 'all') { $this->_pdf->add_object($object, $where); }
47
+
48
+ function serialize_object($id) { $this->_pdf->serialize_object($id); }
49
+
50
+ function reopen_serialized_object($obj) { $this->_pdf->reopen_serialized_object($obj); }
51
+
52
+ //........................................................................
53
+
54
+ function get_width() { return $this->_pdf->get_width(); }
55
+ function get_height() { return $this->_pdf->get_height(); }
56
+ function get_page_number() { return $this->_pdf->get_page_number(); }
57
+ function get_page_count() { return $this->_pdf->get_page_count(); }
58
+
59
+ function set_page_number($num) { $this->_pdf->set_page_number($num); }
60
+ function set_page_count($count) { $this->_pdf->set_page_count($count); }
61
+
62
+ function line($x1, $y1, $x2, $y2, $color, $width, $style = array()) {
63
+ $this->_pdf->line($x1, $y1, $x2, $y2, $color, $width, $style);
64
+ }
65
+
66
+ function rectangle($x1, $y1, $w, $h, $color, $width, $style = array()) {
67
+ $this->_pdf->rectangle($x1, $y1, $w, $h, $color, $width, $style);
68
+ }
69
+
70
+ function filled_rectangle($x1, $y1, $w, $h, $color) {
71
+ $this->_pdf->filled_rectangle($x1, $y1, $w, $h, $color);
72
+ }
73
+
74
+ function polygon($points, $color, $width = null, $style = array(), $fill = false) {
75
+ $this->_pdf->polygon($points, $color, $width, $style, $fill);
76
+ }
77
+
78
+ function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false) {
79
+ $this->_pdf->circle($x, $y, $r1, $color, $width, $style, $fill);
80
+ }
81
+
82
+ function image($img_url, $x, $y, $w = null, $h = null) {
83
+ $this->_pdf->image($img_url, $x, $y, $w, $h);
84
+ }
85
+
86
+ function text($x, $y, $text, $font, $size, $color = array(0,0,0), $adjust = 0, $angle = 0) {
87
+ $this->_fonts[$font] = true;
88
+ $this->_pdf->text($x, $y, $text, $font, $size, $color, $adjust, $angle);
89
+ }
90
+
91
+ function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $adjust = 0, $angle = 0) {
92
+
93
+ // We want to remove this from cached pages since it may not be correct
94
+ $this->_pdf->close_object();
95
+ $this->_pdf->page_text($x, $y, $text, $font, $size, $color, $adjust, $angle);
96
+ $this->_pdf->reopen_object($this->_current_page_id);
97
+ }
98
+
99
+ function page_script($script, $type = 'text/php') {
100
+
101
+ // We want to remove this from cached pages since it may not be correct
102
+ $this->_pdf->close_object();
103
+ $this->_pdf->page_script($script, $type);
104
+ $this->_pdf->reopen_object($this->_current_page_id);
105
+ }
106
+
107
+ function new_page() {
108
+ $this->_pdf->close_object();
109
+
110
+ // Add the object to the current page
111
+ $this->_pdf->add_object($this->_current_page_id, "add");
112
+ $this->_pdf->new_page();
113
+
114
+ Page_Cache::store_page($this->_cache_id,
115
+ $this->_pdf->get_page_number() - 1,
116
+ $this->_pdf->serialize_object($this->_current_page_id));
117
+
118
+ $this->_current_page_id = $this->_pdf->open_object();
119
+ return $this->_current_page_id;
120
+ }
121
+
122
+ function stream($filename) {
123
+ // Store the last page in the page cache
124
+ if ( !is_null($this->_current_page_id) ) {
125
+ $this->_pdf->close_object();
126
+ $this->_pdf->add_object($this->_current_page_id, "add");
127
+ Page_Cache::store_page($this->_cache_id,
128
+ $this->_pdf->get_page_number(),
129
+ $this->_pdf->serialize_object($this->_current_page_id));
130
+ Page_Cache::store_fonts($this->_cache_id, $this->_fonts);
131
+ $this->_current_page_id = null;
132
+ }
133
+
134
+ $this->_pdf->stream($filename);
135
+
136
+ }
137
+
138
+ function &output() {
139
+ // Store the last page in the page cache
140
+ if ( !is_null($this->_current_page_id) ) {
141
+ $this->_pdf->close_object();
142
+ $this->_pdf->add_object($this->_current_page_id, "add");
143
+ Page_Cache::store_page($this->_cache_id,
144
+ $this->_pdf->get_page_number(),
145
+ $this->_pdf->serialize_object($this->_current_page_id));
146
+ $this->_current_page_id = null;
147
+ }
148
+
149
+ return $this->_pdf->output();
150
+ }
151
+
152
+ function get_messages() { return $this->_pdf->get_messages(); }
153
+
154
+ }
dompdf/include/canvas.cls.php ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: canvas.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Main rendering interface
13
+ *
14
+ * Currently {@link CPDF_Adapter}, {@link PDFLib_Adapter}, {@link TCPDF_Adapter}, and {@link GD_Adapter}
15
+ * implement this interface.
16
+ *
17
+ * Implementations should measure x and y increasing to the left and down,
18
+ * respectively, with the origin in the top left corner. Implementations
19
+ * are free to use a unit other than points for length, but I can't
20
+ * guarantee that the results will look any good.
21
+ *
22
+ * @package dompdf
23
+ */
24
+ interface Canvas {
25
+
26
+ /**
27
+ * Returns the current page number
28
+ *
29
+ * @return int
30
+ */
31
+ function get_page_number();
32
+
33
+ /**
34
+ * Returns the total number of pages
35
+ *
36
+ * @return int
37
+ */
38
+ function get_page_count();
39
+
40
+ /**
41
+ * Sets the total number of pages
42
+ *
43
+ * @param int $count
44
+ */
45
+ function set_page_count($count);
46
+
47
+ /**
48
+ * Draws a line from x1,y1 to x2,y2
49
+ *
50
+ * See {@link Style::munge_colour()} for the format of the colour array.
51
+ * See {@link Cpdf::setLineStyle()} for a description of the format of the
52
+ * $style parameter (aka dash).
53
+ *
54
+ * @param float $x1
55
+ * @param float $y1
56
+ * @param float $x2
57
+ * @param float $y2
58
+ * @param array $color
59
+ * @param float $width
60
+ * @param array $style
61
+ */
62
+ function line($x1, $y1, $x2, $y2, $color, $width, $style = null);
63
+
64
+ /**
65
+ * Draws a rectangle at x1,y1 with width w and height h
66
+ *
67
+ * See {@link Style::munge_colour()} for the format of the colour array.
68
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
69
+ * parameter (aka dash)
70
+ *
71
+ * @param float $x1
72
+ * @param float $y1
73
+ * @param float $w
74
+ * @param float $h
75
+ * @param array $color
76
+ * @param float $width
77
+ * @param array $style
78
+ */
79
+ function rectangle($x1, $y1, $w, $h, $color, $width, $style = null);
80
+
81
+ /**
82
+ * Draws a filled rectangle at x1,y1 with width w and height h
83
+ *
84
+ * See {@link Style::munge_colour()} for the format of the colour array.
85
+ *
86
+ * @param float $x1
87
+ * @param float $y1
88
+ * @param float $w
89
+ * @param float $h
90
+ * @param array $color
91
+ */
92
+ function filled_rectangle($x1, $y1, $w, $h, $color);
93
+
94
+ /**
95
+ * Starts a clipping rectangle at x1,y1 with width w and height h
96
+ *
97
+ * @param float $x1
98
+ * @param float $y1
99
+ * @param float $w
100
+ * @param float $h
101
+ */
102
+ function clipping_rectangle($x1, $y1, $w, $h);
103
+
104
+ /**
105
+ * Ends the last clipping shape
106
+ */
107
+ function clipping_end();
108
+
109
+ /**
110
+ * Save current state
111
+ */
112
+ function save();
113
+
114
+ /**
115
+ * Restore last state
116
+ */
117
+ function restore();
118
+
119
+ /**
120
+ * Rotate
121
+ */
122
+ function rotate($angle, $x, $y);
123
+
124
+ /**
125
+ * Skew
126
+ */
127
+ function skew($angle_x, $angle_y, $x, $y);
128
+
129
+ /**
130
+ * Scale
131
+ */
132
+ function scale($s_x, $s_y, $x, $y);
133
+
134
+ /**
135
+ * Translate
136
+ */
137
+ function translate($t_x, $t_y);
138
+
139
+ /**
140
+ * Transform
141
+ */
142
+ function transform($a, $b, $c, $d, $e, $f);
143
+
144
+ /**
145
+ * Draws a polygon
146
+ *
147
+ * The polygon is formed by joining all the points stored in the $points
148
+ * array. $points has the following structure:
149
+ * <code>
150
+ * array(0 => x1,
151
+ * 1 => y1,
152
+ * 2 => x2,
153
+ * 3 => y2,
154
+ * ...
155
+ * );
156
+ * </code>
157
+ *
158
+ * See {@link Style::munge_colour()} for the format of the colour array.
159
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
160
+ * parameter (aka dash)
161
+ *
162
+ * @param array $points
163
+ * @param array $color
164
+ * @param float $width
165
+ * @param array $style
166
+ * @param bool $fill Fills the polygon if true
167
+ */
168
+ function polygon($points, $color, $width = null, $style = null, $fill = false);
169
+
170
+ /**
171
+ * Draws a circle at $x,$y with radius $r
172
+ *
173
+ * See {@link Style::munge_colour()} for the format of the colour array.
174
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
175
+ * parameter (aka dash)
176
+ *
177
+ * @param float $x
178
+ * @param float $y
179
+ * @param float $r
180
+ * @param array $color
181
+ * @param float $width
182
+ * @param array $style
183
+ * @param bool $fill Fills the circle if true
184
+ */
185
+ function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false);
186
+
187
+ /**
188
+ * Add an image to the pdf.
189
+ *
190
+ * The image is placed at the specified x and y coordinates with the
191
+ * given width and height.
192
+ *
193
+ * @param string $img_url the path to the image
194
+ * @param string $img_type the type (e.g. extension) of the image
195
+ * @param float $x x position
196
+ * @param float $y y position
197
+ * @param int $w width (in pixels)
198
+ * @param int $h height (in pixels)
199
+ */
200
+ function image($img_url, $x, $y, $w, $h, $resolution = "normal");
201
+
202
+ /**
203
+ * Writes text at the specified x and y coordinates
204
+ *
205
+ * See {@link Style::munge_colour()} for the format of the colour array.
206
+ *
207
+ * @param float $x
208
+ * @param float $y
209
+ * @param string $text the text to write
210
+ * @param string $font the font file to use
211
+ * @param float $size the font size, in points
212
+ * @param array $color
213
+ * @param float $word_space word spacing adjustment
214
+ * @param float $char_space whar spacing adjustment
215
+ * @param float $angle angle
216
+ */
217
+ function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0, $char_space = 0, $angle = 0);
218
+
219
+ /**
220
+ * Add a named destination (similar to <a name="foo">...</a> in html)
221
+ *
222
+ * @param string $anchorname The name of the named destination
223
+ */
224
+ function add_named_dest($anchorname);
225
+
226
+ /**
227
+ * Add a link to the pdf
228
+ *
229
+ * @param string $url The url to link to
230
+ * @param float $x The x position of the link
231
+ * @param float $y The y position of the link
232
+ * @param float $width The width of the link
233
+ * @param float $height The height of the link
234
+ */
235
+ function add_link($url, $x, $y, $width, $height);
236
+
237
+ /**
238
+ * Add meta information to the pdf
239
+ *
240
+ * @param string $label label of the value (Creator, Producer, etc.)
241
+ * @param string $value the text to set
242
+ */
243
+ function add_info($name, $value);
244
+
245
+ /**
246
+ * Calculates text size, in points
247
+ *
248
+ * @param string $text the text to be sized
249
+ * @param string $font the desired font
250
+ * @param float $size the desired font size
251
+ * @param float $spacing word spacing, if any
252
+ * @return float
253
+ */
254
+ function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0);
255
+
256
+ /**
257
+ * Calculates font height, in points
258
+ *
259
+ * @param string $font
260
+ * @param float $size
261
+ * @return float
262
+ */
263
+ function get_font_height($font, $size);
264
+
265
+ function get_font_baseline($font, $size);
266
+
267
+ /**
268
+ * Returns the font x-height, in points
269
+ *
270
+ * @param string $font
271
+ * @param float $size
272
+ * @return float
273
+ */
274
+ //function get_font_x_height($font, $size);
275
+
276
+ /**
277
+ * Sets the opacity
278
+ *
279
+ * @param float $opacity
280
+ * @param string $mode
281
+ * @return float
282
+ */
283
+ function set_opacity($opacity, $mode = "Normal");
284
+
285
+ /**
286
+ * Sets the default view
287
+ *
288
+ * @param string $view
289
+ *
290
+ * 'XYZ' left, top, zoom
291
+ * 'Fit'
292
+ * 'FitH' top
293
+ * 'FitV' left
294
+ * 'FitR' left,bottom,right
295
+ * 'FitB'
296
+ * 'FitBH' top
297
+ * 'FitBV' left
298
+ */
299
+ function set_default_view($view, $options = array());
300
+
301
+ /**
302
+ * Starts a new page
303
+ *
304
+ * Subsequent drawing operations will appear on the new page.
305
+ */
306
+ function new_page();
307
+
308
+ /**
309
+ * Streams the PDF directly to the browser
310
+ *
311
+ * @param string $filename the name of the PDF file
312
+ * @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
313
+ */
314
+ function stream($filename, $options = null);
315
+
316
+ /**
317
+ * Returns the PDF as a string
318
+ *
319
+ * @param array $options associative array: 'compress' => 1 or 0
320
+ * @return string
321
+ */
322
+ function output($options = null);
323
+
324
+ }
dompdf/include/canvas_factory.cls.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: canvas_factory.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Create canvas instances
12
+ *
13
+ * The canvas factory creates canvas instances based on the
14
+ * availability of rendering backends and config options.
15
+ *
16
+ * @package dompdf
17
+ */
18
+ class Canvas_Factory {
19
+
20
+ /**
21
+ * Constructor is private: this is a static class
22
+ */
23
+ private function __construct() { }
24
+
25
+ /**
26
+ * @param string|array $paper
27
+ * @param string $orientation
28
+ * @param string $class
29
+ *
30
+ * @return Canvas
31
+ */
32
+ static function get_instance($paper = null, $orientation = null, $class = null) {
33
+
34
+ $backend = strtolower(DOMPDF_PDF_BACKEND);
35
+
36
+ if ( isset($class) && class_exists($class, false) )
37
+ $class .= "_Adapter";
38
+
39
+ else if ( (DOMPDF_PDF_BACKEND === "auto" || $backend === "pdflib" ) &&
40
+ class_exists("PDFLib", false) )
41
+ $class = "PDFLib_Adapter";
42
+
43
+ // FIXME The TCPDF adapter is not ready yet
44
+ //else if ( (DOMPDF_PDF_BACKEND === "auto" || $backend === "cpdf") )
45
+ // $class = "CPDF_Adapter";
46
+
47
+ else if ( $backend === "tcpdf")
48
+ $class = "TCPDF_Adapter";
49
+
50
+ else if ( $backend === "gd" )
51
+ $class = "GD_Adapter";
52
+
53
+ else
54
+ $class = "CPDF_Adapter";
55
+
56
+ return new $class($paper, $orientation);
57
+
58
+ }
59
+ }
dompdf/include/cellmap.cls.php ADDED
@@ -0,0 +1,728 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: cellmap.cls.php 464 2012-01-30 20:44:53Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Maps table cells to the table grid.
12
+ *
13
+ * This class resolves borders in tables with collapsed borders and helps
14
+ * place row & column spanned table cells.
15
+ *
16
+ * @access private
17
+ * @package dompdf
18
+ */
19
+ class Cellmap {
20
+
21
+ /**
22
+ * Border style weight lookup for collapsed border resolution.
23
+ *
24
+ * @var array
25
+ */
26
+ static protected $_BORDER_STYLE_SCORE = array("inset" => 1,
27
+ "groove" => 2,
28
+ "outset" => 3,
29
+ "ridge" => 4,
30
+ "dotted" => 5,
31
+ "dashed" => 6,
32
+ "solid" => 7,
33
+ "double" => 8,
34
+ "hidden" => 9,
35
+ "none" => 0);
36
+
37
+ /**
38
+ * The table object this cellmap is attached to.
39
+ *
40
+ * @var Table_Frame_Decorator
41
+ */
42
+ protected $_table;
43
+
44
+ /**
45
+ * The total number of rows in the table
46
+ *
47
+ * @var int
48
+ */
49
+ protected $_num_rows;
50
+
51
+ /**
52
+ * The total number of columns in the table
53
+ *
54
+ * @var int
55
+ */
56
+ protected $_num_cols;
57
+
58
+ /**
59
+ * 2D array mapping <row,column> to frames
60
+ *
61
+ * @var array
62
+ */
63
+ protected $_cells;
64
+
65
+ /**
66
+ * 1D array of column dimensions
67
+ *
68
+ * @var array
69
+ */
70
+ protected $_columns;
71
+
72
+ /**
73
+ * 1D array of row dimensions
74
+ *
75
+ * @var array
76
+ */
77
+ protected $_rows;
78
+
79
+ /**
80
+ * 2D array of border specs
81
+ *
82
+ * @var array
83
+ */
84
+ protected $_borders;
85
+
86
+ /**
87
+ * 1D Array mapping frames to (multiple) <row, col> pairs, keyed on
88
+ * frame_id.
89
+ *
90
+ * @var array
91
+ */
92
+ protected $_frames;
93
+
94
+ /**
95
+ * @var int Current column when adding cells, 0-based
96
+ */
97
+ private $__col;
98
+
99
+ /**
100
+ * @var int Current row when adding cells, 0-based
101
+ */
102
+ private $__row;
103
+
104
+ /**
105
+ * @var bool Tells wether the columns' width can be modified
106
+ */
107
+ private $_columns_locked = false;
108
+
109
+ //........................................................................
110
+
111
+ function __construct(Table_Frame_Decorator $table) {
112
+ $this->_table = $table;
113
+ $this->reset();
114
+ }
115
+
116
+ function __destruct() {
117
+ clear_object($this);
118
+ }
119
+ //........................................................................
120
+
121
+ function reset() {
122
+ $this->_num_rows = 0;
123
+ $this->_num_cols = 0;
124
+
125
+ $this->_cells = array();
126
+ $this->_frames = array();
127
+
128
+ if ( !$this->_columns_locked ) {
129
+ $this->_columns = array();
130
+ }
131
+
132
+ $this->_rows = array();
133
+
134
+ $this->_borders = array();
135
+
136
+ $this->__col = $this->__row = 0;
137
+ }
138
+
139
+ //........................................................................
140
+
141
+ function lock_columns() {
142
+ $this->_columns_locked = true;
143
+ }
144
+
145
+ function is_columns_locked() {
146
+ return $this->_columns_locked;
147
+ }
148
+
149
+ function get_num_rows() { return $this->_num_rows; }
150
+ function get_num_cols() { return $this->_num_cols; }
151
+
152
+ function &get_columns() {
153
+ return $this->_columns;
154
+ }
155
+
156
+ function set_columns($columns) {
157
+ $this->_columns = $columns;
158
+ }
159
+
160
+ function &get_column($i) {
161
+ if ( !isset($this->_columns[$i]) )
162
+ $this->_columns[$i] = array("x" => 0,
163
+ "min-width" => 0,
164
+ "max-width" => 0,
165
+ "used-width" => null,
166
+ "absolute" => 0,
167
+ "percent" => 0,
168
+ "auto" => true);
169
+
170
+ return $this->_columns[$i];
171
+ }
172
+
173
+ function &get_rows() {
174
+ return $this->_rows;
175
+ }
176
+
177
+ function &get_row($j) {
178
+ if ( !isset($this->_rows[$j]) )
179
+ $this->_rows[$j] = array("y" => 0,
180
+ "first-column" => 0,
181
+ "height" => null);
182
+ return $this->_rows[$j];
183
+ }
184
+
185
+ function get_border($i, $j, $h_v, $prop = null) {
186
+ if ( !isset($this->_borders[$i][$j][$h_v]) )
187
+ $this->_borders[$i][$j][$h_v] = array("width" => 0,
188
+ "style" => "solid",
189
+ "color" => "black");
190
+ if ( isset($prop) )
191
+ return $this->_borders[$i][$j][$h_v][$prop];
192
+
193
+ return $this->_borders[$i][$j][$h_v];
194
+ }
195
+
196
+ function get_border_properties($i, $j) {
197
+
198
+ $left = $this->get_border($i, $j, "vertical");
199
+ $right = $this->get_border($i, $j+1, "vertical");
200
+ $top = $this->get_border($i, $j, "horizontal");
201
+ $bottom = $this->get_border($i+1, $j, "horizontal");
202
+
203
+ return compact("top", "bottom", "left", "right");
204
+ }
205
+
206
+ //........................................................................
207
+
208
+ function get_spanned_cells($frame) {
209
+ $key = $frame->get_id();
210
+
211
+ if ( !isset($this->_frames[$key]) ) {
212
+ throw new DOMPDF_Exception("Frame not found in cellmap");
213
+ }
214
+
215
+ return $this->_frames[$key];
216
+
217
+ }
218
+
219
+ function frame_exists_in_cellmap($frame) {
220
+ $key = $frame->get_id();
221
+ return isset($this->_frames[$key]);
222
+ }
223
+
224
+ function get_frame_position($frame) {
225
+ global $_dompdf_warnings;
226
+
227
+ $key = $frame->get_id();
228
+
229
+ if ( !isset($this->_frames[$key]) ) {
230
+ throw new DOMPDF_Exception("Frame not found in cellmap");
231
+ }
232
+
233
+ $col = $this->_frames[$key]["columns"][0];
234
+ $row = $this->_frames[$key]["rows"][0];
235
+
236
+ if ( !isset($this->_columns[$col])) {
237
+ $_dompdf_warnings[] = "Frame not found in columns array. Check your table layout for missing or extra TDs.";
238
+ $x = 0;
239
+ } else
240
+ $x = $this->_columns[$col]["x"];
241
+
242
+ if ( !isset($this->_rows[$row])) {
243
+ $_dompdf_warnings[] = "Frame not found in row array. Check your table layout for missing or extra TDs.";
244
+ $y = 0;
245
+ } else
246
+ $y = $this->_rows[$row]["y"];
247
+
248
+ return array($x, $y, "x" => $x, "y" => $y);
249
+ }
250
+
251
+ function get_frame_width($frame) {
252
+ $key = $frame->get_id();
253
+
254
+ if ( !isset($this->_frames[$key]) ) {
255
+ throw new DOMPDF_Exception("Frame not found in cellmap");
256
+ }
257
+
258
+ $cols = $this->_frames[$key]["columns"];
259
+ $w = 0;
260
+ foreach ($cols as $i)
261
+ $w += $this->_columns[$i]["used-width"];
262
+
263
+ return $w;
264
+
265
+ }
266
+
267
+ function get_frame_height($frame) {
268
+ $key = $frame->get_id();
269
+
270
+ if ( !isset($this->_frames[$key]) ) {
271
+ throw new DOMPDF_Exception("Frame not found in cellmap");
272
+ }
273
+
274
+ $rows = $this->_frames[$key]["rows"];
275
+ $h = 0;
276
+ foreach ($rows as $i) {
277
+ if ( !isset($this->_rows[$i]) ) {
278
+ throw new Exception("foo");
279
+ }
280
+ $h += $this->_rows[$i]["height"];
281
+ }
282
+ return $h;
283
+
284
+ }
285
+
286
+
287
+ //........................................................................
288
+
289
+ function set_column_width($j, $width) {
290
+ if ( $this->_columns_locked ) {
291
+ return;
292
+ }
293
+
294
+ $col =& $this->get_column($j);
295
+ $col["used-width"] = $width;
296
+ $next_col =& $this->get_column($j+1);
297
+ $next_col["x"] = $next_col["x"] + $width;
298
+ }
299
+
300
+ function set_row_height($i, $height) {
301
+ $row =& $this->get_row($i);
302
+
303
+ if ( $row["height"] !== null && $height <= $row["height"] ) {
304
+ return;
305
+ }
306
+
307
+ $row["height"] = $height;
308
+ $next_row =& $this->get_row($i+1);
309
+ $next_row["y"] = $row["y"] + $height;
310
+
311
+ }
312
+
313
+ //........................................................................
314
+
315
+
316
+ protected function _resolve_border($i, $j, $h_v, $border_spec) {
317
+ $n_width = $border_spec["width"];
318
+ $n_style = $border_spec["style"];
319
+ $n_color = $border_spec["color"];
320
+
321
+ if ( !isset($this->_borders[$i][$j][$h_v]) ) {
322
+ $this->_borders[$i][$j][$h_v] = $border_spec;
323
+ return $this->_borders[$i][$j][$h_v]["width"];
324
+ }
325
+
326
+ $border = &$this->_borders[$i][$j][$h_v];
327
+
328
+ $o_width = $border["width"];
329
+ $o_style = $border["style"];
330
+ $o_color = $border["color"];
331
+
332
+ if ( ($n_style === "hidden" ||
333
+ $n_width > $o_width ||
334
+ $o_style === "none")
335
+
336
+ or
337
+
338
+ ($o_width == $n_width &&
339
+ in_array($n_style, self::$_BORDER_STYLE_SCORE) &&
340
+ self::$_BORDER_STYLE_SCORE[ $n_style ] > self::$_BORDER_STYLE_SCORE[ $o_style ]) )
341
+ $border = $border_spec;
342
+
343
+ return $border["width"];
344
+ }
345
+
346
+ //........................................................................
347
+
348
+ function add_frame(Frame $frame) {
349
+
350
+ $style = $frame->get_style();
351
+ $display = $style->display;
352
+
353
+ $collapse = $this->_table->get_style()->border_collapse == "collapse";
354
+
355
+ // Recursively add the frames within tables, table-row-groups and table-rows
356
+ if ( $display === "table-row" ||
357
+ $display === "table" ||
358
+ $display === "inline-table" ||
359
+ in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) {
360
+
361
+ $start_row = $this->__row;
362
+ foreach ( $frame->get_children() as $child )
363
+ $this->add_frame( $child );
364
+
365
+ if ( $display === "table-row" )
366
+ $this->add_row();
367
+
368
+ $num_rows = $this->__row - $start_row - 1;
369
+ $key = $frame->get_id();
370
+
371
+ // Row groups always span across the entire table
372
+ $this->_frames[$key]["columns"] = range(0,max(0,$this->_num_cols-1));
373
+ $this->_frames[$key]["rows"] = range($start_row, max(0, $this->__row - 1));
374
+ $this->_frames[$key]["frame"] = $frame;
375
+
376
+ if ( $display !== "table-row" && $collapse ) {
377
+
378
+ $bp = $style->get_border_properties();
379
+
380
+ // Resolve the borders
381
+ for ( $i = 0; $i < $num_rows+1; $i++) {
382
+ $this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
383
+ $this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
384
+ }
385
+
386
+ for ( $j = 0; $j < $this->_num_cols; $j++) {
387
+ $this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
388
+ $this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
389
+ }
390
+ }
391
+
392
+
393
+ return;
394
+ }
395
+
396
+ $node = $frame->get_node();
397
+
398
+ // Determine where this cell is going
399
+ $colspan = $node->getAttribute("colspan");
400
+ $rowspan = $node->getAttribute("rowspan");
401
+
402
+ if ( !$colspan ) {
403
+ $colspan = 1;
404
+ $node->setAttribute("colspan",1);
405
+ }
406
+
407
+ if ( !$rowspan ) {
408
+ $rowspan = 1;
409
+ $node->setAttribute("rowspan",1);
410
+ }
411
+ $key = $frame->get_id();
412
+
413
+ $bp = $style->get_border_properties();
414
+
415
+
416
+ // Add the frame to the cellmap
417
+ $max_left = $max_right = 0;
418
+
419
+ // Find the next available column (fix by Ciro Mondueri)
420
+ $ac = $this->__col;
421
+ while ( isset($this->_cells[$this->__row][$ac]) )
422
+ $ac++;
423
+ $this->__col = $ac;
424
+
425
+ // Rows:
426
+ for ( $i = 0; $i < $rowspan; $i++ ) {
427
+ $row = $this->__row + $i;
428
+
429
+ $this->_frames[$key]["rows"][] = $row;
430
+
431
+ for ( $j = 0; $j < $colspan; $j++)
432
+ $this->_cells[$row][$this->__col + $j] = $frame;
433
+
434
+ if ( $collapse ) {
435
+ // Resolve vertical borders
436
+ $max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
437
+ $max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
438
+ }
439
+ }
440
+
441
+ $max_top = $max_bottom = 0;
442
+
443
+ // Columns:
444
+ for ( $j = 0; $j < $colspan; $j++ ) {
445
+ $col = $this->__col + $j;
446
+ $this->_frames[$key]["columns"][] = $col;
447
+
448
+ if ( $collapse ) {
449
+ // Resolve horizontal borders
450
+ $max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
451
+ $max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
452
+ }
453
+ }
454
+
455
+ $this->_frames[$key]["frame"] = $frame;
456
+
457
+ // Handle seperated border model
458
+ if ( !$collapse ) {
459
+ list($h, $v) = $this->_table->get_style()->border_spacing;
460
+
461
+ // Border spacing is effectively a margin between cells
462
+ $v = $style->length_in_pt($v) / 2;
463
+ $h = $style->length_in_pt($h) / 2;
464
+ $style->margin = "$v $h";
465
+
466
+ // The additional 1/2 width gets added to the table proper
467
+
468
+ } else {
469
+
470
+ // Drop the frame's actual border
471
+ $style->border_left_width = $max_left / 2;
472
+ $style->border_right_width = $max_right / 2;
473
+ $style->border_top_width = $max_top / 2;
474
+ $style->border_bottom_width = $max_bottom / 2;
475
+ $style->margin = "none";
476
+ }
477
+
478
+ // Resolve the frame's width
479
+ list($frame_min, $frame_max) = $frame->get_min_max_width();
480
+
481
+ $width = $style->width;
482
+
483
+ if ( is_percent($width) ) {
484
+ $var = "percent";
485
+ $val = (float)rtrim($width, "% ") / $colspan;
486
+
487
+ } else if ( $width !== "auto" ) {
488
+ $var = "absolute";
489
+ $val = $style->length_in_pt($frame_min) / $colspan;
490
+ }
491
+
492
+ if (!$this->_columns_locked) {
493
+ $min = 0;
494
+ $max = 0;
495
+ for ( $cs = 0; $cs < $colspan; $cs++ ) {
496
+
497
+ // Resolve the frame's width(s) with other cells
498
+ $col =& $this->get_column( $this->__col + $cs );
499
+
500
+ // Note: $var is either 'percent' or 'absolute'. We compare the
501
+ // requested percentage or absolute values with the existing widths
502
+ // and adjust accordingly.
503
+ if ( isset($var) && $val > $col[$var] ) {
504
+ $col[$var] = $val;
505
+ $col["auto"] = false;
506
+ }
507
+
508
+ $min += $col["min-width"];
509
+ $max += $col["max-width"];
510
+ }
511
+
512
+
513
+ if ( $frame_min > $min ) {
514
+ // The frame needs more space. Expand each sub-column
515
+ $inc = ($frame_min - $min) / $colspan;
516
+ for ($c = 0; $c < $colspan; $c++) {
517
+ $col =& $this->get_column($this->__col + $c);
518
+ $col["min-width"] += $inc;
519
+ }
520
+ }
521
+
522
+ if ( $frame_max > $max ) {
523
+ $inc = ($frame_max - $max) / $colspan;
524
+ for ($c = 0; $c < $colspan; $c++) {
525
+ $col =& $this->get_column($this->__col + $c);
526
+ $col["max-width"] += $inc;
527
+ }
528
+ }
529
+ }
530
+
531
+ $this->__col += $colspan;
532
+ if ( $this->__col > $this->_num_cols )
533
+ $this->_num_cols = $this->__col;
534
+
535
+ }
536
+
537
+ //........................................................................
538
+
539
+ function add_row() {
540
+
541
+ $this->__row++;
542
+ $this->_num_rows++;
543
+
544
+ // Find the next available column
545
+ $i = 0;
546
+ while ( isset($this->_cells[$this->__row][$i]) )
547
+ $i++;
548
+
549
+ $this->__col = $i;
550
+
551
+ }
552
+
553
+ //........................................................................
554
+
555
+ /**
556
+ * Remove a row from the cellmap.
557
+ *
558
+ * @param Frame
559
+ */
560
+ function remove_row(Frame $row) {
561
+
562
+ $key = $row->get_id();
563
+ if ( !isset($this->_frames[$key]) )
564
+ return; // Presumably this row has alredy been removed
565
+
566
+ $this->_row = $this->_num_rows--;
567
+
568
+ $rows = $this->_frames[$key]["rows"];
569
+ $columns = $this->_frames[$key]["columns"];
570
+
571
+ // Remove all frames from this row
572
+ foreach ( $rows as $r ) {
573
+ foreach ( $columns as $c ) {
574
+ if ( isset($this->_cells[$r][$c]) ) {
575
+ $id = $this->_cells[$r][$c]->get_id();
576
+
577
+ $this->_frames[$id] = null;
578
+ unset($this->_frames[$id]);
579
+
580
+ $this->_cells[$r][$c] = null;
581
+ unset($this->_cells[$r][$c]);
582
+ }
583
+ }
584
+ $this->_rows[$r] = null;
585
+ unset($this->_rows[$r]);
586
+ }
587
+
588
+ $this->_frames[$key] = null;
589
+ unset($this->_frames[$key]);
590
+
591
+ }
592
+
593
+ /**
594
+ * Remove a row group from the cellmap.
595
+ *
596
+ * @param Frame $group The group to remove
597
+ */
598
+ function remove_row_group(Frame $group) {
599
+
600
+ $key = $group->get_id();
601
+ if ( !isset($this->_frames[$key]) )
602
+ return; // Presumably this row has alredy been removed
603
+
604
+ $iter = $group->get_first_child();
605
+ while ($iter) {
606
+ $this->remove_row($iter);
607
+ $iter = $iter->get_next_sibling();
608
+ }
609
+
610
+ $this->_frames[$key] = null;
611
+ unset($this->_frames[$key]);
612
+ }
613
+
614
+ /**
615
+ * Update a row group after rows have been removed
616
+ *
617
+ * @param Frame $group The group to update
618
+ * @param Frame $last_row The last row in the row group
619
+ */
620
+ function update_row_group(Frame $group, Frame $last_row) {
621
+
622
+ $g_key = $group->get_id();
623
+ $r_key = $last_row->get_id();
624
+
625
+ $r_rows = $this->_frames[$r_key]["rows"];
626
+ $this->_frames[$g_key]["rows"] = range( $this->_frames[$g_key]["rows"][0], end($r_rows) );
627
+
628
+ }
629
+
630
+ //........................................................................
631
+
632
+ function assign_x_positions() {
633
+ // Pre-condition: widths must be resolved and assigned to columns and
634
+ // column[0]["x"] must be set.
635
+
636
+ if ( $this->_columns_locked ) {
637
+ return;
638
+ }
639
+
640
+ $x = $this->_columns[0]["x"];
641
+ foreach ( array_keys($this->_columns) as $j ) {
642
+ $this->_columns[$j]["x"] = $x;
643
+ $x += $this->_columns[$j]["used-width"];
644
+
645
+ }
646
+
647
+ }
648
+
649
+ function assign_frame_heights() {
650
+ // Pre-condition: widths and heights of each column & row must be
651
+ // calcluated
652
+
653
+ foreach ( $this->_frames as $arr ) {
654
+ $frame = $arr["frame"];
655
+
656
+ $h = 0;
657
+ foreach( $arr["rows"] as $row ) {
658
+ if ( !isset($this->_rows[$row]) )
659
+ // The row has been removed because of a page split, so skip it.
660
+ continue;
661
+ $h += $this->_rows[$row]["height"];
662
+ }
663
+
664
+ if ( $frame instanceof Table_Cell_Frame_Decorator )
665
+ $frame->set_cell_height($h);
666
+ else
667
+ $frame->get_style()->height = $h;
668
+ }
669
+
670
+ }
671
+
672
+ //........................................................................
673
+
674
+ /**
675
+ * Re-adjust frame height if the table height is larger than its content
676
+ */
677
+ function set_frame_heights($table_height, $content_height) {
678
+
679
+
680
+ // Distribute the increased height proportionally amongst each row
681
+ foreach ( $this->_frames as $arr ) {
682
+ $frame = $arr["frame"];
683
+
684
+ $h = 0;
685
+ foreach ($arr["rows"] as $row ) {
686
+ if ( !isset($this->_rows[$row]) )
687
+ continue;
688
+
689
+ $h += $this->_rows[$row]["height"];
690
+ }
691
+
692
+ if ( $content_height > 0 )
693
+ $new_height = ($h / $content_height) * $table_height;
694
+ else
695
+ $new_height = 0;
696
+
697
+ if ( $frame instanceof Table_Cell_Frame_Decorator )
698
+ $frame->set_cell_height($new_height);
699
+ else
700
+ $frame->get_style()->height = $new_height;
701
+ }
702
+
703
+ }
704
+
705
+ //........................................................................
706
+
707
+ // Used for debugging:
708
+ function __toString() {
709
+ $str = "";
710
+ $str .= "Columns:<br/>";
711
+ $str .= pre_r($this->_columns, true);
712
+ $str .= "Rows:<br/>";
713
+ $str .= pre_r($this->_rows, true);
714
+
715
+ $str .= "Frames:<br/>";
716
+ $arr = array();
717
+ foreach ( $this->_frames as $key => $val )
718
+ $arr[$key] = array("columns" => $val["columns"], "rows" => $val["rows"]);
719
+
720
+ $str .= pre_r($arr, true);
721
+
722
+ if ( php_sapi_name() == "cli" )
723
+ $str = strip_tags(str_replace(array("<br/>","<b>","</b>"),
724
+ array("\n",chr(27)."[01;33m", chr(27)."[0m"),
725
+ $str));
726
+ return $str;
727
+ }
728
+ }
dompdf/include/cpdf_adapter.cls.php ADDED
@@ -0,0 +1,850 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Orion Richardson <orionr@yahoo.com>
7
+ * @author Helmut Tischer <htischer@weihenstephan.org>
8
+ * @author Fabien M�nager <fabien.menager@gmail.com>
9
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
10
+ * @version $Id: cpdf_adapter.cls.php 466 2012-02-04 13:08:38Z fabien.menager $
11
+ */
12
+
13
+ // FIXME: Need to sanity check inputs to this class
14
+ require_once(DOMPDF_LIB_DIR . "/class.pdf.php");
15
+
16
+ /**
17
+ * PDF rendering interface
18
+ *
19
+ * CPDF_Adapter provides a simple stateless interface to the stateful one
20
+ * provided by the Cpdf class.
21
+ *
22
+ * Unless otherwise mentioned, all dimensions are in points (1/72 in). The
23
+ * coordinate origin is in the top left corner, and y values increase
24
+ * downwards.
25
+ *
26
+ * See {@link http://www.ros.co.nz/pdf/} for more complete documentation
27
+ * on the underlying {@link Cpdf} class.
28
+ *
29
+ * @package dompdf
30
+ */
31
+ class CPDF_Adapter implements Canvas {
32
+
33
+ /**
34
+ * Dimensions of paper sizes in points
35
+ *
36
+ * @var array;
37
+ */
38
+ static $PAPER_SIZES = array(
39
+ "4a0" => array(0,0,4767.87,6740.79),
40
+ "2a0" => array(0,0,3370.39,4767.87),
41
+ "a0" => array(0,0,2383.94,3370.39),
42
+ "a1" => array(0,0,1683.78,2383.94),
43
+ "a2" => array(0,0,1190.55,1683.78),
44
+ "a3" => array(0,0,841.89,1190.55),
45
+ "a4" => array(0,0,595.28,841.89),
46
+ "a5" => array(0,0,419.53,595.28),
47
+ "a6" => array(0,0,297.64,419.53),
48
+ "a7" => array(0,0,209.76,297.64),
49
+ "a8" => array(0,0,147.40,209.76),
50
+ "a9" => array(0,0,104.88,147.40),
51
+ "a10" => array(0,0,73.70,104.88),
52
+ "b0" => array(0,0,2834.65,4008.19),
53
+ "b1" => array(0,0,2004.09,2834.65),
54
+ "b2" => array(0,0,1417.32,2004.09),
55
+ "b3" => array(0,0,1000.63,1417.32),
56
+ "b4" => array(0,0,708.66,1000.63),
57
+ "b5" => array(0,0,498.90,708.66),
58
+ "b6" => array(0,0,354.33,498.90),
59
+ "b7" => array(0,0,249.45,354.33),
60
+ "b8" => array(0,0,175.75,249.45),
61
+ "b9" => array(0,0,124.72,175.75),
62
+ "b10" => array(0,0,87.87,124.72),
63
+ "c0" => array(0,0,2599.37,3676.54),
64
+ "c1" => array(0,0,1836.85,2599.37),
65
+ "c2" => array(0,0,1298.27,1836.85),
66
+ "c3" => array(0,0,918.43,1298.27),
67
+ "c4" => array(0,0,649.13,918.43),
68
+ "c5" => array(0,0,459.21,649.13),
69
+ "c6" => array(0,0,323.15,459.21),
70
+ "c7" => array(0,0,229.61,323.15),
71
+ "c8" => array(0,0,161.57,229.61),
72
+ "c9" => array(0,0,113.39,161.57),
73
+ "c10" => array(0,0,79.37,113.39),
74
+ "ra0" => array(0,0,2437.80,3458.27),
75
+ "ra1" => array(0,0,1729.13,2437.80),
76
+ "ra2" => array(0,0,1218.90,1729.13),
77
+ "ra3" => array(0,0,864.57,1218.90),
78
+ "ra4" => array(0,0,609.45,864.57),
79
+ "sra0" => array(0,0,2551.18,3628.35),
80
+ "sra1" => array(0,0,1814.17,2551.18),
81
+ "sra2" => array(0,0,1275.59,1814.17),
82
+ "sra3" => array(0,0,907.09,1275.59),
83
+ "sra4" => array(0,0,637.80,907.09),
84
+ "letter" => array(0,0,612.00,792.00),
85
+ "legal" => array(0,0,612.00,1008.00),
86
+ "ledger" => array(0,0,1224.00, 792.00),
87
+ "tabloid" => array(0,0,792.00, 1224.00),
88
+ "executive" => array(0,0,521.86,756.00),
89
+ "folio" => array(0,0,612.00,936.00),
90
+ "commercial #10 envelope" => array(0,0,684,297),
91
+ "catalog #10 1/2 envelope" => array(0,0,648,864),
92
+ "8.5x11" => array(0,0,612.00,792.00),
93
+ "8.5x14" => array(0,0,612.00,1008.0),
94
+ "11x17" => array(0,0,792.00, 1224.00),
95
+ );
96
+
97
+
98
+ /**
99
+ * Instance of Cpdf class
100
+ *
101
+ * @var Cpdf
102
+ */
103
+ private $_pdf;
104
+
105
+ /**
106
+ * PDF width, in points
107
+ *
108
+ * @var float
109
+ */
110
+ private $_width;
111
+
112
+ /**
113
+ * PDF height, in points
114
+ *
115
+ * @var float;
116
+ */
117
+ private $_height;
118
+
119
+ /**
120
+ * Current page number
121
+ *
122
+ * @var int
123
+ */
124
+ private $_page_number;
125
+
126
+ /**
127
+ * Total number of pages
128
+ *
129
+ * @var int
130
+ */
131
+ private $_page_count;
132
+
133
+ /**
134
+ * Text to display on every page
135
+ *
136
+ * @var array
137
+ */
138
+ private $_page_text;
139
+
140
+ /**
141
+ * Array of pages for accesing after rendering is initially complete
142
+ *
143
+ * @var array
144
+ */
145
+ private $_pages;
146
+
147
+ /**
148
+ * Array of temporary cached images to be deleted when processing is complete
149
+ *
150
+ * @var array
151
+ */
152
+ private $_image_cache;
153
+
154
+ /**
155
+ * Class constructor
156
+ *
157
+ * @param mixed $paper The size of paper to use in this PDF ({@link CPDF_Adapter::$PAPER_SIZES})
158
+ * @param string $orientation The orienation of the document (either 'landscape' or 'portrait')
159
+ */
160
+ function __construct($paper = "letter", $orientation = "portrait") {
161
+
162
+ if ( is_array($paper) )
163
+ $size = $paper;
164
+ else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) )
165
+ $size = self::$PAPER_SIZES[mb_strtolower($paper)];
166
+ else
167
+ $size = self::$PAPER_SIZES["letter"];
168
+
169
+ if ( mb_strtolower($orientation) === "landscape" ) {
170
+ list($size[2], $size[3]) = array($size[3], $size[2]);
171
+ }
172
+
173
+ $this->_pdf = new Cpdf($size, DOMPDF_UNICODE_ENABLED, DOMPDF_FONT_CACHE, DOMPDF_TEMP_DIR);
174
+ $this->_pdf->addInfo("Creator", "DOMPDF");
175
+ $time = substr_replace(date('YmdHisO'), '\'', -2, 0).'\'';
176
+ $this->_pdf->addInfo("CreationDate", "D:$time");
177
+ $this->_pdf->addInfo("ModDate", "D:$time");
178
+
179
+ $this->_width = $size[2] - $size[0];
180
+ $this->_height= $size[3] - $size[1];
181
+
182
+ $this->_page_number = $this->_page_count = 1;
183
+ $this->_page_text = array();
184
+
185
+ $this->_pages = array($this->_pdf->getFirstPageId());
186
+
187
+ $this->_image_cache = array();
188
+ }
189
+
190
+ /**
191
+ * Class destructor
192
+ *
193
+ * Deletes all temporary image files
194
+ */
195
+ function __destruct() {
196
+ foreach ($this->_image_cache as $img) {
197
+ //debugpng
198
+ if (DEBUGPNG) print '[__destruct unlink '.$img.']';
199
+ if (!DEBUGKEEPTEMP)
200
+ unlink($img);
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Returns the Cpdf instance
206
+ *
207
+ * @return Cpdf
208
+ */
209
+ function get_cpdf() { return $this->_pdf; }
210
+
211
+ /**
212
+ * Add meta information to the PDF
213
+ *
214
+ * @param string $label label of the value (Creator, Producer, etc.)
215
+ * @param string $value the text to set
216
+ */
217
+ function add_info($label, $value) {
218
+ $this->_pdf->addInfo($label, $value);
219
+ }
220
+
221
+ /**
222
+ * Opens a new 'object'
223
+ *
224
+ * While an object is open, all drawing actions are recored in the object,
225
+ * as opposed to being drawn on the current page. Objects can be added
226
+ * later to a specific page or to several pages.
227
+ *
228
+ * The return value is an integer ID for the new object.
229
+ *
230
+ * @see CPDF_Adapter::close_object()
231
+ * @see CPDF_Adapter::add_object()
232
+ *
233
+ * @return int
234
+ */
235
+ function open_object() {
236
+ $ret = $this->_pdf->openObject();
237
+ $this->_pdf->saveState();
238
+ return $ret;
239
+ }
240
+
241
+ /**
242
+ * Reopens an existing 'object'
243
+ *
244
+ * @see CPDF_Adapter::open_object()
245
+ * @param int $object the ID of a previously opened object
246
+ */
247
+ function reopen_object($object) {
248
+ $this->_pdf->reopenObject($object);
249
+ $this->_pdf->saveState();
250
+ }
251
+
252
+ /**
253
+ * Closes the current 'object'
254
+ *
255
+ * @see CPDF_Adapter::open_object()
256
+ */
257
+ function close_object() {
258
+ $this->_pdf->restoreState();
259
+ $this->_pdf->closeObject();
260
+ }
261
+
262
+ /**
263
+ * Adds a specified 'object' to the document
264
+ *
265
+ * $object int specifying an object created with {@link
266
+ * CPDF_Adapter::open_object()}. $where can be one of:
267
+ * - 'add' add to current page only
268
+ * - 'all' add to every page from the current one onwards
269
+ * - 'odd' add to all odd numbered pages from now on
270
+ * - 'even' add to all even numbered pages from now on
271
+ * - 'next' add the object to the next page only
272
+ * - 'nextodd' add to all odd numbered pages from the next one
273
+ * - 'nexteven' add to all even numbered pages from the next one
274
+ *
275
+ * @see Cpdf::addObject()
276
+ *
277
+ * @param int $object
278
+ * @param string $where
279
+ */
280
+ function add_object($object, $where = 'all') {
281
+ $this->_pdf->addObject($object, $where);
282
+ }
283
+
284
+ /**
285
+ * Stops the specified 'object' from appearing in the document.
286
+ *
287
+ * The object will stop being displayed on the page following the current
288
+ * one.
289
+ *
290
+ * @param int $object
291
+ */
292
+ function stop_object($object) {
293
+ $this->_pdf->stopObject($object);
294
+ }
295
+
296
+ /**
297
+ * @access private
298
+ */
299
+ function serialize_object($id) {
300
+ // Serialize the pdf object's current state for retrieval later
301
+ return $this->_pdf->serializeObject($id);
302
+ }
303
+
304
+ /**
305
+ * @access private
306
+ */
307
+ function reopen_serialized_object($obj) {
308
+ return $this->_pdf->restoreSerializedObject($obj);
309
+ }
310
+
311
+ //........................................................................
312
+
313
+ /**
314
+ * Returns the PDF's width in points
315
+ * @return float
316
+ */
317
+ function get_width() { return $this->_width; }
318
+
319
+ /**
320
+ * Returns the PDF's height in points
321
+ * @return float
322
+ */
323
+ function get_height() { return $this->_height; }
324
+
325
+ /**
326
+ * Returns the current page number
327
+ * @return int
328
+ */
329
+ function get_page_number() { return $this->_page_number; }
330
+
331
+ /**
332
+ * Returns the total number of pages in the document
333
+ * @return int
334
+ */
335
+ function get_page_count() { return $this->_page_count; }
336
+
337
+ /**
338
+ * Sets the current page number
339
+ *
340
+ * @param int $num
341
+ */
342
+ function set_page_number($num) { $this->_page_number = $num; }
343
+
344
+ /**
345
+ * Sets the page count
346
+ *
347
+ * @param int $count
348
+ */
349
+ function set_page_count($count) { $this->_page_count = $count; }
350
+
351
+ /**
352
+ * Sets the stroke colour
353
+ *
354
+ * See {@link Style::set_colour()} for the format of the color array.
355
+ * @param array $color
356
+ */
357
+ protected function _set_stroke_color($color) {
358
+ $this->_pdf->setStrokeColor($color);
359
+ }
360
+
361
+ /**
362
+ * Sets the fill colour
363
+ *
364
+ * See {@link Style::set_colour()} for the format of the colour array.
365
+ * @param array $color
366
+ */
367
+ protected function _set_fill_color($color) {
368
+ $this->_pdf->setColor($color);
369
+ }
370
+
371
+ /**
372
+ * Sets line transparency
373
+ * @see Cpdf::setLineTransparency()
374
+ *
375
+ * Valid blend modes are (case-sensitive):
376
+ *
377
+ * Normal, Multiply, Screen, Overlay, Darken, Lighten,
378
+ * ColorDodge, ColorBurn, HardLight, SoftLight, Difference,
379
+ * Exclusion
380
+ *
381
+ * @param string $mode the blending mode to use
382
+ * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
383
+ */
384
+ protected function _set_line_transparency($mode, $opacity) {
385
+ $this->_pdf->setLineTransparency($mode, $opacity);
386
+ }
387
+
388
+ /**
389
+ * Sets fill transparency
390
+ * @see Cpdf::setFillTransparency()
391
+ *
392
+ * Valid blend modes are (case-sensitive):
393
+ *
394
+ * Normal, Multiply, Screen, Overlay, Darken, Lighten,
395
+ * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
396
+ * Exclusion
397
+ *
398
+ * @param string $mode the blending mode to use
399
+ * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
400
+ */
401
+ protected function _set_fill_transparency($mode, $opacity) {
402
+ $this->_pdf->setFillTransparency($mode, $opacity);
403
+ }
404
+
405
+ /**
406
+ * Sets the line style
407
+ *
408
+ * @see Cpdf::setLineStyle()
409
+ *
410
+ * @param float width
411
+ * @param string cap
412
+ * @param string join
413
+ * @param array dash
414
+ */
415
+ protected function _set_line_style($width, $cap, $join, $dash) {
416
+ $this->_pdf->setLineStyle($width, $cap, $join, $dash);
417
+ }
418
+
419
+ /**
420
+ * Sets the opacity
421
+ *
422
+ * @param $opacity
423
+ * @param $mode
424
+ */
425
+ function set_opacity($opacity, $mode = "Normal") {
426
+ $this->_set_line_transparency($mode, $opacity);
427
+ $this->_set_fill_transparency($mode, $opacity);
428
+ }
429
+
430
+ function set_default_view($view, $options = array()) {
431
+ array_unshift($options, $view);
432
+ $currentPage = $this->_pdf->currentPage;
433
+ call_user_func_array(array($this->_pdf, "openHere"), $options);
434
+ }
435
+
436
+ //........................................................................
437
+
438
+
439
+ /**
440
+ * Remaps y coords from 4th to 1st quadrant
441
+ *
442
+ * @param float $y
443
+ * @return float
444
+ */
445
+ protected function y($y) { return $this->_height - $y; }
446
+
447
+ // Canvas implementation
448
+
449
+ function line($x1, $y1, $x2, $y2, $color, $width, $style = array()) {
450
+ //pre_r(compact("x1", "y1", "x2", "y2", "color", "width", "style"));
451
+
452
+ $this->_set_stroke_color($color);
453
+ $this->_set_line_style($width, "butt", "", $style);
454
+ $this->_pdf->line($x1, $this->y($y1),
455
+ $x2, $this->y($y2));
456
+ }
457
+
458
+ //........................................................................
459
+
460
+ /**
461
+ * Convert a GIF or BMP image to a PNG image
462
+ *
463
+ * @return string The url of the newly converted image
464
+ */
465
+ protected function _convert_gif_bmp_to_png($image_url, $type) {
466
+ $image_type = Image_Cache::type_to_ext($type);
467
+ $func_name = "imagecreatefrom$image_type";
468
+
469
+ if ( !function_exists($func_name) ) {
470
+ throw new DOMPDF_Exception("Function $func_name() not found. Cannot convert $image_type image: $image_url. Please install the image PHP extension.");
471
+ }
472
+
473
+ set_error_handler("record_warnings");
474
+ $im = $func_name($image_url);
475
+
476
+ if ( $im ) {
477
+ imageinterlace($im, false);
478
+
479
+ $tempname = tempnam(DOMPDF_TEMP_DIR, "{$image_type}dompdf_img_");
480
+ @unlink($tempname);
481
+ $filename = "$tempname.png";
482
+ $this->_image_cache[] = $filename;
483
+
484
+ imagepng($im, $filename);
485
+ imagedestroy($im);
486
+ }
487
+ else {
488
+ $filename = Image_Cache::$broken_image;
489
+ }
490
+
491
+ restore_error_handler();
492
+
493
+ return $filename;
494
+ }
495
+
496
+ function rectangle($x1, $y1, $w, $h, $color, $width, $style = array()) {
497
+ $this->_set_stroke_color($color);
498
+ $this->_set_line_style($width, "butt", "", $style);
499
+ $this->_pdf->rectangle($x1, $this->y($y1) - $h, $w, $h);
500
+ }
501
+
502
+ //........................................................................
503
+
504
+ function filled_rectangle($x1, $y1, $w, $h, $color) {
505
+ $this->_set_fill_color($color);
506
+ $this->_pdf->filledRectangle($x1, $this->y($y1) - $h, $w, $h);
507
+ }
508
+
509
+ function clipping_rectangle($x1, $y1, $w, $h) {
510
+ $this->_pdf->clippingRectangle($x1, $this->y($y1) - $h, $w, $h);
511
+ }
512
+
513
+ function clipping_end() {
514
+ $this->_pdf->clippingEnd();
515
+ }
516
+
517
+ function save() {
518
+ $this->_pdf->saveState();
519
+ }
520
+
521
+ function restore() {
522
+ $this->_pdf->restoreState();
523
+ }
524
+
525
+ function rotate($angle, $x, $y) {
526
+ $this->_pdf->rotate($angle, $x, $y);
527
+ }
528
+
529
+ function skew($angle_x, $angle_y, $x, $y) {
530
+ $this->_pdf->skew($angle_x, $angle_y, $x, $y);
531
+ }
532
+
533
+ function scale($s_x, $s_y, $x, $y) {
534
+ $this->_pdf->scale($s_x, $s_y, $x, $y);
535
+ }
536
+
537
+ function translate($t_x, $t_y) {
538
+ $this->_pdf->translate($t_x, $t_y);
539
+ }
540
+
541
+ function transform($a, $b, $c, $d, $e, $f) {
542
+ $this->_pdf->transform(array($a, $b, $c, $d, $e, $f));
543
+ }
544
+
545
+ //........................................................................
546
+
547
+ function polygon($points, $color, $width = null, $style = array(), $fill = false) {
548
+ $this->_set_fill_color($color);
549
+ $this->_set_stroke_color($color);
550
+
551
+ // Adjust y values
552
+ for ( $i = 1; $i < count($points); $i += 2)
553
+ $points[$i] = $this->y($points[$i]);
554
+
555
+ $this->_pdf->polygon($points, count($points) / 2, $fill);
556
+ }
557
+
558
+ //........................................................................
559
+
560
+ function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false) {
561
+ $this->_set_fill_color($color);
562
+ $this->_set_stroke_color($color);
563
+
564
+ if ( !$fill && isset($width) )
565
+ $this->_set_line_style($width, "round", "round", $style);
566
+
567
+ $this->_pdf->ellipse($x, $this->y($y), $r1, 0, 0, 8, 0, 360, 1, $fill);
568
+ }
569
+
570
+ //........................................................................
571
+
572
+ function image($img, $x, $y, $w, $h, $resolution = "normal") {
573
+ list($width, $height, $type) = dompdf_getimagesize($img);
574
+
575
+ //debugpng
576
+ if (DEBUGPNG) print "[image:$img|$width|$height|$type]";
577
+
578
+ switch ($type) {
579
+ case IMAGETYPE_JPEG:
580
+ if (DEBUGPNG) print '!!!jpg!!!';
581
+ $this->_pdf->addJpegFromFile($img, $x, $this->y($y) - $h, $w, $h);
582
+ break;
583
+
584
+ case IMAGETYPE_GIF:
585
+ case IMAGETYPE_BMP:
586
+ if (DEBUGPNG) print '!!!bmp or gif!!!';
587
+ // @todo use cache for BMP and GIF
588
+ $img = $this->_convert_gif_bmp_to_png($img, $type);
589
+
590
+ case IMAGETYPE_PNG:
591
+ if (DEBUGPNG) print '!!!png!!!';
592
+
593
+ $this->_pdf->addPngFromFile($img, $x, $this->y($y) - $h, $w, $h);
594
+ break;
595
+
596
+ default:
597
+ if (DEBUGPNG) print '!!!unknown!!!';
598
+ }
599
+ }
600
+
601
+ //........................................................................
602
+
603
+ function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0, $char_space = 0, $angle = 0) {
604
+ $pdf = $this->_pdf;
605
+
606
+ $pdf->setColor($color);
607
+
608
+ $font .= ".afm";
609
+ $pdf->selectFont($font);
610
+
611
+ //Font_Metrics::get_font_height($font, $size) ==
612
+ //$this->get_font_height($font, $size) ==
613
+ //$this->_pdf->selectFont($font),$this->_pdf->getFontHeight($size)
614
+ //- FontBBoxheight+FontHeightOffset, scaled to $size, in pt
615
+ //$this->_pdf->getFontDescender($size)
616
+ //- Descender scaled to size
617
+ //
618
+ //$this->_pdf->fonts[$this->_pdf->currentFont] sizes:
619
+ //['FontBBox'][0] left, ['FontBBox'][1] bottom, ['FontBBox'][2] right, ['FontBBox'][3] top
620
+ //Maximum extent of all glyphs of the font from the baseline point
621
+ //['Ascender'] maximum height above baseline except accents
622
+ //['Descender'] maximum depth below baseline, negative number means below baseline
623
+ //['FontHeightOffset'] manual enhancement of .afm files to trim windows fonts. currently not used.
624
+ //Values are in 1/1000 pt for a font size of 1 pt
625
+ //
626
+ //['FontBBox'][1] should be close to ['Descender']
627
+ //['FontBBox'][3] should be close to ['Ascender']+Accents
628
+ //in practice, FontBBox values are a little bigger
629
+ //
630
+ //The text position is referenced to the baseline, not to the lower corner of the FontBBox,
631
+ //for what the left,top corner is given.
632
+ //FontBBox spans also the background box for the text.
633
+ //If the lower corner would be used as reference point, the Descents of the glyphs would
634
+ //hang over the background box border.
635
+ //Therefore compensate only the extent above the Baseline.
636
+ //
637
+ //print '<pre>['.$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'].']</pre>';
638
+ //
639
+ //$pdf->addText($x, $this->y($y) - ($pdf->fonts[$pdf->currentFont]['FontBBox'][3]*$size)/1000, $size, $text, $angle, $word_space, $char_space);
640
+ $pdf->addText($x, $this->y($y) - $pdf->getFontHeight($size), $size, $text, $angle, $word_space, $char_space);
641
+ }
642
+
643
+ //........................................................................
644
+
645
+ function javascript($code) {
646
+ $this->_pdf->addJavascript($code);
647
+ }
648
+
649
+ //........................................................................
650
+
651
+ /**
652
+ * Add a named destination (similar to <a name="foo">...</a> in html)
653
+ *
654
+ * @param string $anchorname The name of the named destination
655
+ */
656
+ function add_named_dest($anchorname) {
657
+ $this->_pdf->addDestination($anchorname, "Fit");
658
+ }
659
+
660
+ //........................................................................
661
+
662
+ /**
663
+ * Add a link to the pdf
664
+ *
665
+ * @param string $url The url to link to
666
+ * @param float $x The x position of the link
667
+ * @param float $y The y position of the link
668
+ * @param float $width The width of the link
669
+ * @param float $height The height of the link
670
+ */
671
+ function add_link($url, $x, $y, $width, $height) {
672
+
673
+ $y = $this->y($y) - $height;
674
+
675
+ if ( strpos($url, '#') === 0 ) {
676
+ // Local link
677
+ $name = substr($url,1);
678
+ if ( $name )
679
+ $this->_pdf->addInternalLink($name, $x, $y, $x + $width, $y + $height);
680
+
681
+ } else {
682
+ $this->_pdf->addLink(rawurldecode($url), $x, $y, $x + $width, $y + $height);
683
+ }
684
+ }
685
+
686
+ //........................................................................
687
+
688
+ function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0) {
689
+ $this->_pdf->selectFont($font);
690
+ if (!DOMPDF_UNICODE_ENABLED) {
691
+ $text = mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
692
+ }
693
+ return $this->_pdf->getTextWidth($size, $text, $word_spacing, $char_spacing);
694
+ }
695
+
696
+ function register_string_subset($font, $string) {
697
+ return $this->_pdf->registerText($font, $string);
698
+ }
699
+
700
+ //........................................................................
701
+
702
+ function get_font_height($font, $size) {
703
+ $this->_pdf->selectFont($font);
704
+ return $this->_pdf->getFontHeight($size) * DOMPDF_FONT_HEIGHT_RATIO;
705
+ }
706
+
707
+ /*function get_font_x_height($font, $size) {
708
+ $this->_pdf->selectFont($font);
709
+ return $this->_pdf->getFontXHeight($size) * DOMPDF_FONT_HEIGHT_RATIO;
710
+ }*/
711
+
712
+ function get_font_baseline($font, $size) {
713
+ return $this->get_font_height($font, $size) / DOMPDF_FONT_HEIGHT_RATIO;
714
+ }
715
+
716
+ //........................................................................
717
+
718
+ /**
719
+ * Writes text at the specified x and y coordinates on every page
720
+ *
721
+ * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
722
+ * with their current values.
723
+ *
724
+ * See {@link Style::munge_colour()} for the format of the colour array.
725
+ *
726
+ * @param float $x
727
+ * @param float $y
728
+ * @param string $text the text to write
729
+ * @param string $font the font file to use
730
+ * @param float $size the font size, in points
731
+ * @param array $color
732
+ * @param float $adjust word spacing adjustment
733
+ * @param float $angle angle to write the text at, measured CW starting from the x-axis
734
+ */
735
+ function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $adjust = 0, $angle = 0) {
736
+ $_t = "text";
737
+ $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "adjust", "angle");
738
+ }
739
+
740
+ //........................................................................
741
+
742
+ /**
743
+ * Processes a script on every page
744
+ *
745
+ * The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available.
746
+ *
747
+ * This function can be used to add page numbers to all pages
748
+ * after the first one, for example.
749
+ *
750
+ * @param string $code the script code
751
+ * @param string $type the language type for script
752
+ */
753
+ function page_script($code, $type = "text/php") {
754
+ $_t = "script";
755
+ $this->_page_text[] = compact("_t", "code", "type");
756
+ }
757
+
758
+ //........................................................................
759
+
760
+ function new_page() {
761
+ $this->_page_number++;
762
+ $this->_page_count++;
763
+
764
+ $ret = $this->_pdf->newPage();
765
+ $this->_pages[] = $ret;
766
+ return $ret;
767
+ }
768
+
769
+ //........................................................................
770
+
771
+ /**
772
+ * Add text to each page after rendering is complete
773
+ */
774
+ protected function _add_page_text() {
775
+
776
+ if ( !count($this->_page_text) )
777
+ return;
778
+
779
+ $page_number = 1;
780
+ $eval = null;
781
+
782
+ foreach ($this->_pages as $pid) {
783
+ $this->reopen_object($pid);
784
+
785
+ foreach ($this->_page_text as $pt) {
786
+ extract($pt);
787
+
788
+ switch ($_t) {
789
+
790
+ case "text":
791
+ $text = str_replace(array("{PAGE_NUM}","{PAGE_COUNT}"),
792
+ array($page_number, $this->_page_count), $text);
793
+ $this->text($x, $y, $text, $font, $size, $color, $adjust, $angle);
794
+ break;
795
+
796
+ case "script":
797
+ if (!$eval) {
798
+ $eval = new PHP_Evaluator($this);
799
+ }
800
+ $eval->evaluate($code, array('PAGE_NUM' => $page_number, 'PAGE_COUNT' => $this->_page_count));
801
+ break;
802
+ }
803
+ }
804
+
805
+ $this->close_object();
806
+ $page_number++;
807
+ }
808
+ }
809
+
810
+ /**
811
+ * Streams the PDF directly to the browser
812
+ *
813
+ * @param string $filename the name of the PDF file
814
+ * @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
815
+ */
816
+ function stream($filename, $options = null) {
817
+ // Add page text
818
+ $this->_add_page_text();
819
+
820
+ $options["Content-Disposition"] = $filename;
821
+ $this->_pdf->stream($options);
822
+ }
823
+
824
+ //........................................................................
825
+
826
+ /**
827
+ * Returns the PDF as a string
828
+ *
829
+ * @param array $options Output options
830
+ * @return string
831
+ */
832
+ function output($options = null) {
833
+ // Add page text
834
+ $this->_add_page_text();
835
+
836
+ $debug = isset($options["compress"]) && $options["compress"] != 1;
837
+
838
+ return $this->_pdf->output($debug);
839
+ }
840
+
841
+ //........................................................................
842
+
843
+ /**
844
+ * Returns logging messages generated by the Cpdf class
845
+ *
846
+ * @return string
847
+ */
848
+ function get_messages() { return $this->_pdf->messages; }
849
+
850
+ }
dompdf/include/css_color.cls.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: css_color.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ class CSS_Color {
12
+ static $cssColorNames = array(
13
+ "aliceblue" => "F0F8FF",
14
+ "antiquewhite" => "FAEBD7",
15
+ "aqua" => "00FFFF",
16
+ "aquamarine" => "7FFFD4",
17
+ "azure" => "F0FFFF",
18
+ "beige" => "F5F5DC",
19
+ "bisque" => "FFE4C4",
20
+ "black" => "000000",
21
+ "blanchedalmond" => "FFEBCD",
22
+ "blue" => "0000FF",
23
+ "blueviolet" => "8A2BE2",
24
+ "brown" => "A52A2A",
25
+ "burlywood" => "DEB887",
26
+ "cadetblue" => "5F9EA0",
27
+ "chartreuse" => "7FFF00",
28
+ "chocolate" => "D2691E",
29
+ "coral" => "FF7F50",
30
+ "cornflowerblue" => "6495ED",
31
+ "cornsilk" => "FFF8DC",
32
+ "crimson" => "DC143C",
33
+ "cyan" => "00FFFF",
34
+ "darkblue" => "00008B",
35
+ "darkcyan" => "008B8B",
36
+ "darkgoldenrod" => "B8860B",
37
+ "darkgray" => "A9A9A9",
38
+ "darkgreen" => "006400",
39
+ "darkgrey" => "A9A9A9",
40
+ "darkkhaki" => "BDB76B",
41
+ "darkmagenta" => "8B008B",
42
+ "darkolivegreen" => "556B2F",
43
+ "darkorange" => "FF8C00",
44
+ "darkorchid" => "9932CC",
45
+ "darkred" => "8B0000",
46
+ "darksalmon" => "E9967A",
47
+ "darkseagreen" => "8FBC8F",
48
+ "darkslateblue" => "483D8B",
49
+ "darkslategray" => "2F4F4F",
50
+ "darkslategrey" => "2F4F4F",
51
+ "darkturquoise" => "00CED1",
52
+ "darkviolet" => "9400D3",
53
+ "deeppink" => "FF1493",
54
+ "deepskyblue" => "00BFFF",
55
+ "dimgray" => "696969",
56
+ "dimgrey" => "696969",
57
+ "dodgerblue" => "1E90FF",
58
+ "firebrick" => "B22222",
59
+ "floralwhite" => "FFFAF0",
60
+ "forestgreen" => "228B22",
61
+ "fuchsia" => "FF00FF",
62
+ "gainsboro" => "DCDCDC",
63
+ "ghostwhite" => "F8F8FF",
64
+ "gold" => "FFD700",
65
+ "goldenrod" => "DAA520",
66
+ "gray" => "808080",
67
+ "green" => "008000",
68
+ "greenyellow" => "ADFF2F",
69
+ "grey" => "808080",
70
+ "honeydew" => "F0FFF0",
71
+ "hotpink" => "FF69B4",
72
+ "indianred" => "CD5C5C",
73
+ "indigo" => "4B0082",
74
+ "ivory" => "FFFFF0",
75
+ "khaki" => "F0E68C",
76
+ "lavender" => "E6E6FA",
77
+ "lavenderblush" => "FFF0F5",
78
+ "lawngreen" => "7CFC00",
79
+ "lemonchiffon" => "FFFACD",
80
+ "lightblue" => "ADD8E6",
81
+ "lightcoral" => "F08080",
82
+ "lightcyan" => "E0FFFF",
83
+ "lightgoldenrodyellow" => "FAFAD2",
84
+ "lightgray" => "D3D3D3",
85
+ "lightgreen" => "90EE90",
86
+ "lightgrey" => "D3D3D3",
87
+ "lightpink" => "FFB6C1",
88
+ "lightsalmon" => "FFA07A",
89
+ "lightseagreen" => "20B2AA",
90
+ "lightskyblue" => "87CEFA",
91
+ "lightslategray" => "778899",
92
+ "lightslategrey" => "778899",
93
+ "lightsteelblue" => "B0C4DE",
94
+ "lightyellow" => "FFFFE0",
95
+ "lime" => "00FF00",
96
+ "limegreen" => "32CD32",
97
+ "linen" => "FAF0E6",
98
+ "magenta" => "FF00FF",
99
+ "maroon" => "800000",
100
+ "mediumaquamarine" => "66CDAA",
101
+ "mediumblue" => "0000CD",
102
+ "mediumorchid" => "BA55D3",
103
+ "mediumpurple" => "9370DB",
104
+ "mediumseagreen" => "3CB371",
105
+ "mediumslateblue" => "7B68EE",
106
+ "mediumspringgreen" => "00FA9A",
107
+ "mediumturquoise" => "48D1CC",
108
+ "mediumvioletred" => "C71585",
109
+ "midnightblue" => "191970",
110
+ "mintcream" => "F5FFFA",
111
+ "mistyrose" => "FFE4E1",
112
+ "moccasin" => "FFE4B5",
113
+ "navajowhite" => "FFDEAD",
114
+ "navy" => "000080",
115
+ "oldlace" => "FDF5E6",
116
+ "olive" => "808000",
117
+ "olivedrab" => "6B8E23",
118
+ "orange" => "FFA500",
119
+ "orangered" => "FF4500",
120
+ "orchid" => "DA70D6",
121
+ "palegoldenrod" => "EEE8AA",
122
+ "palegreen" => "98FB98",
123
+ "paleturquoise" => "AFEEEE",
124
+ "palevioletred" => "DB7093",
125
+ "papayawhip" => "FFEFD5",
126
+ "peachpuff" => "FFDAB9",
127
+ "peru" => "CD853F",
128
+ "pink" => "FFC0CB",
129
+ "plum" => "DDA0DD",
130
+ "powderblue" => "B0E0E6",
131
+ "purple" => "800080",
132
+ "red" => "FF0000",
133
+ "rosybrown" => "BC8F8F",
134
+ "royalblue" => "4169E1",
135
+ "saddlebrown" => "8B4513",
136
+ "salmon" => "FA8072",
137
+ "sandybrown" => "F4A460",
138
+ "seagreen" => "2E8B57",
139
+ "seashell" => "FFF5EE",
140
+ "sienna" => "A0522D",
141
+ "silver" => "C0C0C0",
142
+ "skyblue" => "87CEEB",
143
+ "slateblue" => "6A5ACD",
144
+ "slategray" => "708090",
145
+ "slategrey" => "708090",
146
+ "snow" => "FFFAFA",
147
+ "springgreen" => "00FF7F",
148
+ "steelblue" => "4682B4",
149
+ "tan" => "D2B48C",
150
+ "teal" => "008080",
151
+ "thistle" => "D8BFD8",
152
+ "tomato" => "FF6347",
153
+ "turquoise" => "40E0D0",
154
+ "violet" => "EE82EE",
155
+ "wheat" => "F5DEB3",
156
+ "white" => "FFFFFF",
157
+ "whitesmoke" => "F5F5F5",
158
+ "yellow" => "FFFF00",
159
+ "yellowgreen" => "9ACD32",
160
+ );
161
+
162
+ static function parse($colour) {
163
+ if ( is_array($colour) )
164
+ // Assume the array has the right format...
165
+ // FIXME: should/could verify this.
166
+ return $colour;
167
+
168
+ $colour = strtolower($colour);
169
+
170
+ if ( in_array($colour, array("transparent", "inherit")) )
171
+ return $colour;
172
+
173
+ if (isset(self::$cssColorNames[$colour]))
174
+ return self::getArray(self::$cssColorNames[$colour]);
175
+
176
+ $length = mb_strlen($colour);
177
+
178
+ // #rgb format
179
+ if ( $length == 4 && $colour[0] === "#" ) {
180
+ return self::getArray($colour[1].$colour[1].$colour[2].$colour[2].$colour[3].$colour[3]);
181
+
182
+ // #rrggbb format
183
+ } else if ( $length == 7 && $colour[0] === "#" ) {
184
+ return self::getArray(mb_substr($colour, 1, 6));
185
+
186
+ // rgb( r,g,b ) format
187
+ } else if ( mb_strpos($colour, "rgb") !== false ) {
188
+ $i = mb_strpos($colour, "(");
189
+ $j = mb_strpos($colour, ")");
190
+
191
+ // Bad colour value
192
+ if ($i === false || $j === false)
193
+ return null;
194
+
195
+ $triplet = explode(",", mb_substr($colour, $i+1, $j-$i-1));
196
+
197
+ if (count($triplet) != 3)
198
+ return null;
199
+
200
+ foreach (array_keys($triplet) as $c) {
201
+ $triplet[$c] = trim($triplet[$c]);
202
+
203
+ if ( $triplet[$c][mb_strlen($triplet[$c]) - 1] === "%" )
204
+ $triplet[$c] = round($triplet[$c] * 2.55);
205
+ }
206
+
207
+ return self::getArray(vsprintf("%02X%02X%02X", $triplet));
208
+
209
+ // cmyk( c,m,y,k ) format
210
+ // http://www.w3.org/TR/css3-gcpm/#cmyk-colors
211
+ } else if ( mb_strpos($colour, "cmyk") !== false ) {
212
+ $i = mb_strpos($colour, "(");
213
+ $j = mb_strpos($colour, ")");
214
+
215
+ // Bad colour value
216
+ if ($i === false || $j === false)
217
+ return null;
218
+
219
+ $values = explode(",", mb_substr($colour, $i+1, $j-$i-1));
220
+
221
+ if (count($values) != 4)
222
+ return null;
223
+
224
+ foreach ($values as &$c) {
225
+ $c = floatval(trim($c));
226
+ if ($c > 1.0) $c = 1.0;
227
+ if ($c < 0.0) $c = 0.0;
228
+ }
229
+
230
+ return self::getArray($values);
231
+ }
232
+ }
233
+
234
+ static function getArray($colour) {
235
+ $c = array(null, null, null, null, "hex" => null);
236
+
237
+ if (is_array($colour)) {
238
+ $c = $colour;
239
+ $c["c"] = $c[0];
240
+ $c["m"] = $c[1];
241
+ $c["y"] = $c[2];
242
+ $c["k"] = $c[3];
243
+ $c["hex"] = "cmyk($c[0],$c[1],$c[2],$c[3])";
244
+ }
245
+ else {
246
+ $c[0] = hexdec(mb_substr($colour, 0, 2)) / 0xff;
247
+ $c[1] = hexdec(mb_substr($colour, 2, 2)) / 0xff;
248
+ $c[2] = hexdec(mb_substr($colour, 4, 2)) / 0xff;
249
+ $c["r"] = $c[0];
250
+ $c["g"] = $c[1];
251
+ $c["b"] = $c[2];
252
+ $c["hex"] = "#$colour";
253
+ }
254
+
255
+ return $c;
256
+ }
257
+ }
dompdf/include/dompdf.cls.php ADDED
@@ -0,0 +1,935 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: dompdf.cls.php 468 2012-02-05 10:51:40Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * DOMPDF - PHP5 HTML to PDF renderer
13
+ *
14
+ * DOMPDF loads HTML and does its best to render it as a PDF. It gets its
15
+ * name from the new DomDocument PHP5 extension. Source HTML is first
16
+ * parsed by a DomDocument object. DOMPDF takes the resulting DOM tree and
17
+ * attaches a {@link Frame} object to each node. {@link Frame} objects store
18
+ * positioning and layout information and each has a reference to a {@link
19
+ * Style} object.
20
+ *
21
+ * Style information is loaded and parsed (see {@link Stylesheet}) and is
22
+ * applied to the frames in the tree by using XPath. CSS selectors are
23
+ * converted into XPath queries, and the computed {@link Style} objects are
24
+ * applied to the {@link Frame}s.
25
+ *
26
+ * {@link Frame}s are then decorated (in the design pattern sense of the
27
+ * word) based on their CSS display property ({@link
28
+ * http://www.w3.org/TR/CSS21/visuren.html#propdef-display}).
29
+ * Frame_Decorators augment the basic {@link Frame} class by adding
30
+ * additional properties and methods specific to the particular type of
31
+ * {@link Frame}. For example, in the CSS layout model, block frames
32
+ * (display: block;) contain line boxes that are usually filled with text or
33
+ * other inline frames. The Block_Frame_Decorator therefore adds a $lines
34
+ * property as well as methods to add {@link Frame}s to lines and to add
35
+ * additional lines. {@link Frame}s also are attached to specific
36
+ * Positioner and {@link Frame_Reflower} objects that contain the
37
+ * positioining and layout algorithm for a specific type of frame,
38
+ * respectively. This is an application of the Strategy pattern.
39
+ *
40
+ * Layout, or reflow, proceeds recursively (post-order) starting at the root
41
+ * of the document. Space constraints (containing block width & height) are
42
+ * pushed down, and resolved positions and sizes bubble up. Thus, every
43
+ * {@link Frame} in the document tree is traversed once (except for tables
44
+ * which use a two-pass layout algorithm). If you are interested in the
45
+ * details, see the reflow() method of the Reflower classes.
46
+ *
47
+ * Rendering is relatively straightforward once layout is complete. {@link
48
+ * Frame}s are rendered using an adapted {@link Cpdf} class, originally
49
+ * written by Wayne Munro, http://www.ros.co.nz/pdf/. (Some performance
50
+ * related changes have been made to the original {@link Cpdf} class, and
51
+ * the {@link CPDF_Adapter} class provides a simple, stateless interface to
52
+ * PDF generation.) PDFLib support has now also been added, via the {@link
53
+ * PDFLib_Adapter}.
54
+ *
55
+ *
56
+ * @package dompdf
57
+ */
58
+ class DOMPDF {
59
+
60
+ /**
61
+ * DomDocument representing the HTML document
62
+ *
63
+ * @var DomDocument
64
+ */
65
+ protected $_xml;
66
+
67
+ /**
68
+ * Frame_Tree derived from the DOM tree
69
+ *
70
+ * @var Frame_Tree
71
+ */
72
+ protected $_tree;
73
+
74
+ /**
75
+ * Stylesheet for the document
76
+ *
77
+ * @var Stylesheet
78
+ */
79
+ protected $_css;
80
+
81
+ /**
82
+ * Actual PDF renderer
83
+ *
84
+ * @var Canvas
85
+ */
86
+ protected $_pdf;
87
+
88
+ /**
89
+ * Desired paper size ('letter', 'legal', 'A4', etc.)
90
+ *
91
+ * @var string
92
+ */
93
+ protected $_paper_size;
94
+
95
+ /**
96
+ * Paper orientation ('portrait' or 'landscape')
97
+ *
98
+ * @var string
99
+ */
100
+ protected $_paper_orientation;
101
+
102
+ /**
103
+ * Callbacks on new page and new element
104
+ *
105
+ * @var array
106
+ */
107
+ protected $_callbacks;
108
+
109
+ /**
110
+ * Experimental caching capability
111
+ *
112
+ * @var string
113
+ */
114
+ private $_cache_id;
115
+
116
+ /**
117
+ * Base hostname
118
+ *
119
+ * Used for relative paths/urls
120
+ * @var string
121
+ */
122
+ protected $_base_host;
123
+
124
+ /**
125
+ * Absolute base path
126
+ *
127
+ * Used for relative paths/urls
128
+ * @var string
129
+ */
130
+ protected $_base_path;
131
+
132
+ /**
133
+ * Protcol used to request file (file://, http://, etc)
134
+ *
135
+ * @var string
136
+ */
137
+ protected $_protocol;
138
+
139
+ /**
140
+ * HTTP context created with stream_context_create()
141
+ * Will be used for file_get_contents
142
+ *
143
+ * @var resource
144
+ */
145
+ protected $_http_context;
146
+
147
+ /**
148
+ * Timestamp of the script start time
149
+ *
150
+ * @var int
151
+ */
152
+ private $_start_time = null;
153
+
154
+ /**
155
+ * @var string The system's locale
156
+ */
157
+ private $_system_locale = null;
158
+
159
+ /**
160
+ * @var bool Tells if the system's locale is the C standard one
161
+ */
162
+ private $_locale_standard = false;
163
+
164
+ /**
165
+ * @var string The default view of the PDF in the viewer
166
+ */
167
+ private $_default_view = "Fit";
168
+
169
+ /**
170
+ * @var array The default view options of the PDF in the viewer
171
+ */
172
+ private $_default_view_options = array();
173
+
174
+ /**
175
+ * @var bool Tells wether the DOM document is in quirksmode (experimental)
176
+ */
177
+ private $_quirksmode = false;
178
+
179
+ public static $native_fonts = array("courier", "courier-bold", "courier-oblique", "courier-boldoblique",
180
+ "helvetica", "helvetica-bold", "helvetica-oblique", "helvetica-boldoblique",
181
+ "times-roman", "times-bold", "times-italic", "times-bolditalic",
182
+ "symbol", "zapfdinbats");
183
+
184
+ /**
185
+ * Class constructor
186
+ */
187
+ function __construct() {
188
+ $this->_locale_standard = sprintf('%.1f', 1.0) == '1.0';
189
+
190
+ $this->save_locale();
191
+
192
+ $this->_messages = array();
193
+ $this->_css = new Stylesheet($this);
194
+ $this->_pdf = null;
195
+ $this->_paper_size = "letter";
196
+ $this->_paper_orientation = "portrait";
197
+ $this->_base_protocol = "";
198
+ $this->_base_host = "";
199
+ $this->_base_path = "";
200
+ $this->_http_context = null;
201
+ $this->_callbacks = array();
202
+ $this->_cache_id = null;
203
+
204
+ $this->restore_locale();
205
+ }
206
+
207
+ /**
208
+ * Class destructor
209
+ */
210
+ function __destruct() {
211
+ clear_object($this);
212
+ }
213
+
214
+ /**
215
+ * Save the system's locale configuration and
216
+ * set the right value for numeric formatting
217
+ */
218
+ private function save_locale() {
219
+ if ( $this->_locale_standard ) return;
220
+
221
+ $this->_system_locale = setlocale(LC_NUMERIC, "C");
222
+ }
223
+
224
+ /**
225
+ * Restore the system's locale configuration
226
+ */
227
+ private function restore_locale() {
228
+ if ( $this->_locale_standard ) return;
229
+
230
+ setlocale(LC_NUMERIC, $this->_system_locale);
231
+ }
232
+
233
+ /**
234
+ * Returns the underlying {@link Frame_Tree} object
235
+ *
236
+ * @return Frame_Tree
237
+ */
238
+ function get_tree() { return $this->_tree; }
239
+
240
+ /**
241
+ * Sets the protocol to use
242
+ * FIXME validate these
243
+ *
244
+ * @param string $proto
245
+ */
246
+ function set_protocol($proto) { $this->_protocol = $proto; }
247
+
248
+ /**
249
+ * Sets the base hostname
250
+ *
251
+ * @param string $host
252
+ */
253
+ function set_host($host) { $this->_base_host = $host; }
254
+
255
+ /**
256
+ * Sets the base path
257
+ *
258
+ * @param string $path
259
+ */
260
+ function set_base_path($path) { $this->_base_path = $path; }
261
+
262
+ /**
263
+ * Sets the HTTP context
264
+ *
265
+ * @param resource $http_context
266
+ */
267
+ function set_http_context($http_context) { $this->_http_context = $http_context; }
268
+
269
+ /**
270
+ * Sets the default view
271
+ *
272
+ * @param string $default_view
273
+ */
274
+ function set_default_view($default_view, $options) {
275
+ $this->_default_view = $default_view;
276
+ $this->_default_view_options = $options;
277
+ }
278
+
279
+ /**
280
+ * Returns the protocol in use
281
+ *
282
+ * @return string
283
+ */
284
+ function get_protocol() { return $this->_protocol; }
285
+
286
+ /**
287
+ * Returns the base hostname
288
+ *
289
+ * @return string
290
+ */
291
+ function get_host() { return $this->_base_host; }
292
+
293
+ /**
294
+ * Returns the base path
295
+ *
296
+ * @return string
297
+ */
298
+ function get_base_path() { return $this->_base_path; }
299
+
300
+ /**
301
+ * Returns the HTTP context
302
+ *
303
+ * @return resource
304
+ */
305
+ function get_http_context() { return $this->_http_context; }
306
+
307
+ /**
308
+ * Return the underlying Canvas instance (e.g. CPDF_Adapter, GD_Adapter)
309
+ *
310
+ * @return Canvas
311
+ */
312
+ function get_canvas() { return $this->_pdf; }
313
+
314
+ /**
315
+ * Returns the callbacks array
316
+ *
317
+ * @return array
318
+ */
319
+ function get_callbacks() { return $this->_callbacks; }
320
+
321
+ /**
322
+ * Returns the stylesheet
323
+ *
324
+ * @return Stylesheet
325
+ */
326
+ function get_css() { return $this->_css; }
327
+
328
+ /**
329
+ * Loads an HTML file
330
+ *
331
+ * Parse errors are stored in the global array _dompdf_warnings.
332
+ *
333
+ * @param string $file a filename or url to load
334
+ */
335
+ function load_html_file($file) {
336
+ $this->save_locale();
337
+
338
+ // Store parsing warnings as messages (this is to prevent output to the
339
+ // browser if the html is ugly and the dom extension complains,
340
+ // preventing the pdf from being streamed.)
341
+ if ( !$this->_protocol && !$this->_base_host && !$this->_base_path )
342
+ list($this->_protocol, $this->_base_host, $this->_base_path) = explode_url($file);
343
+
344
+ if ( !DOMPDF_ENABLE_REMOTE &&
345
+ ($this->_protocol != "" && $this->_protocol !== "file://" ) )
346
+ throw new DOMPDF_Exception("Remote file requested, but DOMPDF_ENABLE_REMOTE is false.");
347
+
348
+ if ($this->_protocol == "" || $this->_protocol === "file://") {
349
+
350
+ $realfile = realpath($file);
351
+ if ( !$file )
352
+ throw new DOMPDF_Exception("File '$file' not found.");
353
+
354
+ if ( strpos($realfile, DOMPDF_CHROOT) !== 0 )
355
+ throw new DOMPDF_Exception("Permission denied on $file.");
356
+
357
+ // Exclude dot files (e.g. .htaccess)
358
+ if ( substr(basename($realfile),0,1) === "." )
359
+ throw new DOMPDF_Exception("Permission denied on $file.");
360
+
361
+ $file = $realfile;
362
+ }
363
+
364
+ $contents = file_get_contents($file, null, $this->_http_context);
365
+ $encoding = null;
366
+
367
+ // See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
368
+ if ( isset($http_response_header) ) {
369
+ foreach($http_response_header as $_header) {
370
+ if ( preg_match("@Content-Type:\s*[\w/]+;\s*?charset=([^\s]+)@i", $_header, $matches) ) {
371
+ $encoding = strtoupper($matches[1]);
372
+ break;
373
+ }
374
+ }
375
+ }
376
+
377
+ $this->restore_locale();
378
+
379
+ $this->load_html($contents, $encoding);
380
+ }
381
+
382
+ /**
383
+ * Loads an HTML string
384
+ *
385
+ * Parse errors are stored in the global array _dompdf_warnings.
386
+ *
387
+ * @todo use the $encoding variable
388
+ * @param string $str HTML text to load
389
+ */
390
+ function load_html($str, $encoding = null) {
391
+ $this->save_locale();
392
+
393
+ // FIXME: Determine character encoding, switch to UTF8, update meta tag. Need better http/file stream encoding detection, currently relies on text or meta tag.
394
+ mb_detect_order('auto');
395
+
396
+ if (mb_detect_encoding($str) !== 'UTF-8') {
397
+ $metatags = array(
398
+ '@<meta\s+http-equiv="Content-Type"\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))?@i',
399
+ '@<meta\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))"?\s+http-equiv="Content-Type"@i',
400
+ '@<meta [^>]*charset\s*=\s*["\']?\s*([^"\' ]+)@i',
401
+ );
402
+
403
+ foreach($metatags as $metatag) {
404
+ if (preg_match($metatag, $str, $matches)) break;
405
+ }
406
+
407
+ if (mb_detect_encoding($str) == '') {
408
+ if (isset($matches[1])) {
409
+ $encoding = strtoupper($matches[1]);
410
+ } else {
411
+ $encoding = 'UTF-8';
412
+ }
413
+ } else {
414
+ if (isset($matches[1])) {
415
+ $encoding = strtoupper($matches[1]);
416
+ } else {
417
+ $encoding = 'auto';
418
+ }
419
+ }
420
+
421
+ if ($encoding !== 'UTF-8') {
422
+ $str = mb_convert_encoding($str, 'UTF-8', $encoding);
423
+ }
424
+
425
+ if (isset($matches[1])) {
426
+ $str = preg_replace('/charset=([^\s"]+)/i', 'charset=UTF-8', $str);
427
+ } else {
428
+ $str = str_replace('<head>', '<head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">', $str);
429
+ }
430
+ } else {
431
+ $encoding = 'UTF-8';
432
+ }
433
+
434
+ // remove BOM mark from UTF-8, it's treated as document text by DOMDocument
435
+ // 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)?
436
+ if (substr($str, 0, 3) == chr(0xEF).chr(0xBB).chr(0xBF)) {
437
+ $str = substr($str, 3);
438
+ }
439
+
440
+ // Parse embedded php, first-pass
441
+ if ( DOMPDF_ENABLE_PHP ) {
442
+ ob_start();
443
+ eval("?" . ">$str");
444
+ $str = ob_get_clean();
445
+ }
446
+
447
+ // if the document contains non utf-8 with a utf-8 meta tag chars and was
448
+ // detected as utf-8 by mbstring, problems could happen.
449
+ // http://devzone.zend.com/article/8855
450
+ if ( $encoding !== 'UTF-8' ) {
451
+ $re = '/<meta ([^>]*)((?:charset=[^"\' ]+)([^>]*)|(?:charset=["\'][^"\' ]+["\']))([^>]*)>/i';
452
+ $str = preg_replace($re, '<meta $1$3>', $str);
453
+ }
454
+
455
+ // Store parsing warnings as messages
456
+ set_error_handler("record_warnings");
457
+
458
+ // @todo Take the quirksmode into account
459
+ // http://hsivonen.iki.fi/doctype/
460
+ // https://developer.mozilla.org/en/mozilla's_quirks_mode
461
+ $quirksmode = false;
462
+
463
+ if ( DOMPDF_ENABLE_HTML5PARSER ) {
464
+ $tokenizer = new HTML5_Tokenizer($str);
465
+ $tokenizer->parse();
466
+ $doc = $tokenizer->save();
467
+
468
+ // Remove #text children nodes in nodes that shouldn't have
469
+ $tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr");
470
+ foreach($tag_names as $tag_name) {
471
+ $nodes = $doc->getElementsByTagName($tag_name);
472
+
473
+ foreach($nodes as $node) {
474
+ self::remove_text_nodes($node);
475
+ }
476
+ }
477
+
478
+ $quirksmode = ($tokenizer->getTree()->getQuirksMode() > HTML5_TreeBuilder::NO_QUIRKS);
479
+ }
480
+ else {
481
+ $doc = new DOMDocument();
482
+ $doc->preserveWhiteSpace = true;
483
+ $doc->loadHTML($str);
484
+
485
+ // If some text is before the doctype of before the <html> tag, we are in quirksmode
486
+ if ( preg_match("/^(.+)<(!doctype|html)/i", ltrim($str), $matches) ) {
487
+ $quirksmode = true;
488
+ }
489
+ else {
490
+ // HTML5 <!DOCTYPE html>
491
+ if ( !$doc->doctype->publicId && !$doc->doctype->systemId ) {
492
+ $quirksmode = false;
493
+ }
494
+
495
+ // not XHTML
496
+ if ( !preg_match("/xhtml/i", $doc->doctype->publicId) ) {
497
+ $quirksmode = true;
498
+ }
499
+ }
500
+ }
501
+
502
+ $this->_xml = $doc;
503
+ $this->_quirksmode = $quirksmode;
504
+
505
+ $this->_tree = new Frame_Tree($this->_xml);
506
+
507
+ restore_error_handler();
508
+
509
+ $this->restore_locale();
510
+ }
511
+
512
+ static function remove_text_nodes(DOMNode $node) {
513
+ $children = array();
514
+ for ($i = 0; $i < $node->childNodes->length; $i++) {
515
+ $child = $node->childNodes->item($i);
516
+ if ( $child->nodeName === "#text" ) {
517
+ $children[] = $child;
518
+ }
519
+ }
520
+
521
+ foreach($children as $child) {
522
+ $node->removeChild($child);
523
+ }
524
+ }
525
+
526
+ /**
527
+ * Builds the {@link Frame_Tree}, loads any CSS and applies the styles to
528
+ * the {@link Frame_Tree}
529
+ */
530
+ protected function _process_html() {
531
+ $this->save_locale();
532
+
533
+ $this->_tree->build_tree();
534
+
535
+ $this->_css->load_css_file(Stylesheet::DEFAULT_STYLESHEET, Stylesheet::ORIG_UA);
536
+
537
+ $acceptedmedia = Stylesheet::$ACCEPTED_GENERIC_MEDIA_TYPES;
538
+ if ( defined("DOMPDF_DEFAULT_MEDIA_TYPE") ) {
539
+ $acceptedmedia[] = DOMPDF_DEFAULT_MEDIA_TYPE;
540
+ } else {
541
+ $acceptedmedia[] = Stylesheet::$ACCEPTED_DEFAULT_MEDIA_TYPE;
542
+ }
543
+
544
+ // load <link rel="STYLESHEET" ... /> tags
545
+ $links = $this->_xml->getElementsByTagName("link");
546
+ foreach ($links as $link) {
547
+ if ( mb_strtolower($link->getAttribute("rel")) === "stylesheet" ||
548
+ mb_strtolower($link->getAttribute("type")) === "text/css" ) {
549
+ //Check if the css file is for an accepted media type
550
+ //media not given then always valid
551
+ $formedialist = preg_split("/[\s\n,]/", $link->getAttribute("media"),-1, PREG_SPLIT_NO_EMPTY);
552
+ if ( count($formedialist) > 0 ) {
553
+ $accept = false;
554
+ foreach ( $formedialist as $type ) {
555
+ if ( in_array(mb_strtolower(trim($type)), $acceptedmedia) ) {
556
+ $accept = true;
557
+ break;
558
+ }
559
+ }
560
+ if (!$accept) {
561
+ //found at least one mediatype, but none of the accepted ones
562
+ //Skip this css file.
563
+ continue;
564
+ }
565
+ }
566
+
567
+ $url = $link->getAttribute("href");
568
+ $url = build_url($this->_protocol, $this->_base_host, $this->_base_path, $url);
569
+
570
+ $this->_css->load_css_file($url, Stylesheet::ORIG_AUTHOR);
571
+ }
572
+
573
+ }
574
+
575
+ // Set the base path of the Stylesheet to that of the file being processed
576
+ $this->_css->set_protocol($this->_protocol);
577
+ $this->_css->set_host($this->_base_host);
578
+ $this->_css->set_base_path($this->_base_path);
579
+
580
+ // load <style> tags
581
+ $styles = $this->_xml->getElementsByTagName("style");
582
+ foreach ($styles as $style) {
583
+
584
+ // Accept all <style> tags by default (note this is contrary to W3C
585
+ // HTML 4.0 spec:
586
+ // http://www.w3.org/TR/REC-html40/present/styles.html#adef-media
587
+ // which states that the default media type is 'screen'
588
+ if ( $style->hasAttributes() &&
589
+ ($media = $style->getAttribute("media")) &&
590
+ !in_array($media, $acceptedmedia) )
591
+ continue;
592
+
593
+ $css = "";
594
+ if ( $style->hasChildNodes() ) {
595
+
596
+ $child = $style->firstChild;
597
+ while ( $child ) {
598
+ $css .= $child->nodeValue; // Handle <style><!-- blah --></style>
599
+ $child = $child->nextSibling;
600
+ }
601
+
602
+ } else
603
+ $css = $style->nodeValue;
604
+
605
+ $this->_css->load_css($css);
606
+ }
607
+
608
+ $this->restore_locale();
609
+ }
610
+
611
+ /**
612
+ * Sets the paper size & orientation
613
+ *
614
+ * @param string $size 'letter', 'legal', 'A4', etc. {@link CPDF_Adapter::$PAPER_SIZES}
615
+ * @param string $orientation 'portrait' or 'landscape'
616
+ */
617
+ function set_paper($size, $orientation = "portrait") {
618
+ $this->_paper_size = $size;
619
+ $this->_paper_orientation = $orientation;
620
+ }
621
+
622
+ /**
623
+ * Enable experimental caching capability
624
+ * @access private
625
+ */
626
+ function enable_caching($cache_id) {
627
+ $this->_cache_id = $cache_id;
628
+ }
629
+
630
+ /**
631
+ * Sets callbacks for events like rendering of pages and elements.
632
+ * The callbacks array contains arrays with 'event' set to 'begin_page',
633
+ * 'end_page', 'begin_frame', or 'end_frame' and 'f' set to a function or
634
+ * object plus method to be called.
635
+ *
636
+ * The function 'f' must take an array as argument, which contains info
637
+ * about the event.
638
+ *
639
+ * @param array $callbacks the set of callbacks to set
640
+ */
641
+ function set_callbacks($callbacks) {
642
+ if (is_array($callbacks)) {
643
+ $this->_callbacks = array();
644
+ foreach ($callbacks as $c) {
645
+ if (is_array($c) && isset($c['event']) && isset($c['f'])) {
646
+ $event = $c['event'];
647
+ $f = $c['f'];
648
+ if (is_callable($f) && is_string($event)) {
649
+ $this->_callbacks[$event][] = $f;
650
+ }
651
+ }
652
+ }
653
+ }
654
+ }
655
+
656
+ /**
657
+ * Get the quirks mode
658
+ *
659
+ * @return boolean true if quirks mode is active
660
+ */
661
+ function get_quirksmode(){
662
+ return $this->_quirksmode;
663
+ }
664
+
665
+ function parse_default_view($value) {
666
+ $valid = array("XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV");
667
+
668
+ $options = preg_split("/\s*,\s*/", trim($value));
669
+ $default_view = array_shift($options);
670
+
671
+ if ( !in_array($default_view, $valid) ) {
672
+ return false;
673
+ }
674
+
675
+ $this->set_default_view($default_view, $options);
676
+ return true;
677
+ }
678
+
679
+ /**
680
+ * Renders the HTML to PDF
681
+ */
682
+ function render() {
683
+ $this->save_locale();
684
+
685
+ if ( DOMPDF_LOG_OUTPUT_FILE ) {
686
+ if ( !file_exists(DOMPDF_LOG_OUTPUT_FILE) && is_writable(dirname(DOMPDF_LOG_OUTPUT_FILE)) ) {
687
+ touch(DOMPDF_LOG_OUTPUT_FILE);
688
+ }
689
+
690
+ $this->_start_time = microtime(true);
691
+ ob_start();
692
+ }
693
+
694
+ //enable_mem_profile();
695
+
696
+ $this->_process_html();
697
+
698
+ $this->_css->apply_styles($this->_tree);
699
+
700
+ // @page style rules : size, margins
701
+ $page_styles = $this->_css->get_page_styles();
702
+
703
+ $base_page_style = $page_styles["base"];
704
+ unset($page_styles["base"]);
705
+
706
+ foreach($page_styles as $_page_style) {
707
+ $_page_style->inherit($base_page_style);
708
+ }
709
+
710
+ if ( is_array($base_page_style->size) ) {
711
+ $this->set_paper(array(0, 0, $base_page_style->size[0], $base_page_style->size[1]));
712
+ }
713
+
714
+ $this->_pdf = Canvas_Factory::get_instance($this->_paper_size, $this->_paper_orientation);
715
+ Font_Metrics::init($this->_pdf);
716
+
717
+ if (DOMPDF_ENABLE_FONTSUBSETTING && $this->_pdf instanceof CPDF_Adapter) {
718
+ foreach ($this->_tree->get_frames() as $frame) {
719
+ $style = $frame->get_style();
720
+ $node = $frame->get_node();
721
+
722
+ // Handle text nodes
723
+ if ( $node->nodeName === "#text" ) {
724
+ $this->_pdf->register_string_subset($style->font_family, $node->nodeValue);
725
+ continue;
726
+ }
727
+
728
+ // Handle generated content (list items)
729
+ if ( $style->display === "list-item" ) {
730
+ $chars = List_Bullet_Renderer::get_counter_chars($style->list_style_type);
731
+ $this->_pdf->register_string_subset($style->font_family, $chars);
732
+ continue;
733
+ }
734
+
735
+ // TODO Handle other generated content (pseudo elements)
736
+ }
737
+ }
738
+
739
+ $root = null;
740
+
741
+ foreach ($this->_tree->get_frames() as $frame) {
742
+ // Set up the root frame
743
+ if ( is_null($root) ) {
744
+ $root = Frame_Factory::decorate_root( $this->_tree->get_root(), $this );
745
+ continue;
746
+ }
747
+
748
+ // Create the appropriate decorators, reflowers & positioners.
749
+ $deco = Frame_Factory::decorate_frame($frame, $this);
750
+ $deco->set_root($root);
751
+
752
+ // FIXME: handle generated content
753
+ if ( $frame->get_style()->display === "list-item" ) {
754
+ // Insert a list-bullet frame
755
+ $node = $this->_xml->createElement("bullet"); // arbitrary choice
756
+ $b_f = new Frame($node);
757
+
758
+ $parent_node = $frame->get_parent()->get_node();
759
+
760
+ if ( !$parent_node->hasAttribute("dompdf-children-count") ) {
761
+ $xpath = new DOMXPath($this->_xml);
762
+ $count = $xpath->query("li", $parent_node)->length;
763
+ $parent_node->setAttribute("dompdf-children-count", $count);
764
+ }
765
+
766
+ if ( !$parent_node->hasAttribute("dompdf-counter") ) {
767
+ $index = ($parent_node->hasAttribute("start") ? $parent_node->getAttribute("start")-1 : 0);
768
+ }
769
+ else {
770
+ $index = $parent_node->getAttribute("dompdf-counter");
771
+ }
772
+
773
+ $index++;
774
+ $parent_node->setAttribute("dompdf-counter", $index);
775
+
776
+ $node->setAttribute("dompdf-counter", $index);
777
+ $style = $this->_css->create_style();
778
+ $style->display = "-dompdf-list-bullet";
779
+ $style->inherit($frame->get_style());
780
+ $b_f->set_style($style);
781
+
782
+ $deco->prepend_child( Frame_Factory::decorate_frame($b_f, $this) );
783
+ }
784
+
785
+ }
786
+
787
+ // Add meta information
788
+ $title = $this->_xml->getElementsByTagName("title");
789
+ if ( $title->length ) {
790
+ $this->_pdf->add_info("Title", trim($title->item(0)->nodeValue));
791
+ }
792
+
793
+ $metas = $this->_xml->getElementsByTagName("meta");
794
+ $labels = array(
795
+ "author" => "Author",
796
+ "keywords" => "Keywords",
797
+ "description" => "Subject",
798
+ );
799
+ foreach($metas as $meta) {
800
+ $name = mb_strtolower($meta->getAttribute("name"));
801
+ $value = trim($meta->getAttribute("content"));
802
+
803
+ if ( isset($labels[$name]) ) {
804
+ $this->_pdf->add_info($labels[$name], $value);
805
+ continue;
806
+ }
807
+
808
+ if ( $name === "dompdf.view" && $this->parse_default_view($value) ) {
809
+ $this->_pdf->set_default_view($this->_default_view, $this->_default_view_options);
810
+ }
811
+ }
812
+
813
+ $root->set_containing_block(0, 0, $this->_pdf->get_width(), $this->_pdf->get_height());
814
+ $root->set_renderer(new Renderer($this));
815
+
816
+ // This is where the magic happens:
817
+ $root->reflow();
818
+
819
+ // Clean up cached images
820
+ Image_Cache::clear();
821
+
822
+ global $_dompdf_warnings, $_dompdf_show_warnings;
823
+ if ( $_dompdf_show_warnings ) {
824
+ echo '<b>DOMPDF Warnings</b><br><pre>';
825
+ foreach ($_dompdf_warnings as $msg)
826
+ echo $msg . "\n";
827
+ echo $this->get_canvas()->get_cpdf()->messages;
828
+ echo '</pre>';
829
+ flush();
830
+ }
831
+
832
+ $this->restore_locale();
833
+ }
834
+
835
+ /**
836
+ * Add meta information to the PDF after rendering
837
+ */
838
+ function add_info($label, $value) {
839
+ if (!is_null($this->_pdf))
840
+ $this->_pdf->add_info($label, $value);
841
+ }
842
+
843
+ /**
844
+ * Writes the output buffer in the log file
845
+ * @return void
846
+ */
847
+ private function write_log() {
848
+ if ( !DOMPDF_LOG_OUTPUT_FILE || !is_writable(DOMPDF_LOG_OUTPUT_FILE) ) return;
849
+
850
+ $frames = Frame::$ID_COUNTER;
851
+ $memory = DOMPDF_memory_usage();
852
+ $memory = number_format($memory/1024);
853
+ $time = number_format((microtime(true) - $this->_start_time) * 1000, 2);
854
+
855
+ $out =
856
+ "<span style='color: #000'>{$frames} frames</span>\t".
857
+ "<span style='color: #900'>{$memory} KB</span>\t".
858
+ "<span style='color: #090'>{$time} ms</span>\t".
859
+ "<span style='color: #009' title='Quirksmode'>".
860
+ ($this->_quirksmode ? "<span style='color: #c00'>ON</span>" : "<span style='color: #0c0'>OFF</span>").
861
+ "</span><br />";
862
+
863
+ $out .= ob_get_clean();
864
+ file_put_contents(DOMPDF_LOG_OUTPUT_FILE, $out);
865
+ }
866
+
867
+ /**
868
+ * Streams the PDF to the client
869
+ *
870
+ * The file will open a download dialog by default. The options
871
+ * parameter controls the output. Accepted options are:
872
+ *
873
+ * 'Accept-Ranges' => 1 or 0 - if this is not set to 1, then this
874
+ * header is not included, off by default this header seems to
875
+ * have caused some problems despite the fact that it is supposed
876
+ * to solve them, so I am leaving it off by default.
877
+ *
878
+ * 'compress' = > 1 or 0 - apply content stream compression, this is
879
+ * on (1) by default
880
+ *
881
+ * 'Attachment' => 1 or 0 - if 1, force the browser to open a
882
+ * download dialog, on (1) by default
883
+ *
884
+ * @param string $filename the name of the streamed file
885
+ * @param array $options header options (see above)
886
+ */
887
+ function stream($filename, $options = null) {
888
+ $this->save_locale();
889
+
890
+ $this->write_log();
891
+
892
+ if (!is_null($this->_pdf))
893
+ $this->_pdf->stream($filename, $options);
894
+
895
+ $this->restore_locale();
896
+ }
897
+
898
+ /**
899
+ * Returns the PDF as a string
900
+ *
901
+ * The file will open a download dialog by default. The options
902
+ * parameter controls the output. Accepted options are:
903
+ *
904
+ *
905
+ * 'compress' = > 1 or 0 - apply content stream compression, this is
906
+ * on (1) by default
907
+ *
908
+ *
909
+ * @param array $options options (see above)
910
+ * @return string
911
+ */
912
+ function output($options = null) {
913
+ $this->save_locale();
914
+
915
+ $this->write_log();
916
+
917
+ if ( is_null($this->_pdf) )
918
+ return null;
919
+
920
+ $output = $this->_pdf->output( $options );
921
+
922
+ $this->restore_locale();
923
+
924
+ return $output;
925
+ }
926
+
927
+ /**
928
+ * Returns the underlying HTML document as a string
929
+ *
930
+ * @return string
931
+ */
932
+ function output_html() {
933
+ return $this->_xml->saveHTML();
934
+ }
935
+ }
dompdf/include/dompdf_exception.cls.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: dompdf_exception.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Standard exception thrown by DOMPDF classes
12
+ *
13
+ * @package dompdf
14
+ */
15
+ class DOMPDF_Exception extends Exception {
16
+
17
+ /**
18
+ * Class constructor
19
+ *
20
+ * @param string $message Error message
21
+ * @param int $code Error code
22
+ */
23
+ function __construct($message = null, $code = 0) {
24
+ parent::__construct($message, $code);
25
+ }
26
+
27
+ }
dompdf/include/dompdf_image_exception.cls.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: dompdf_image_exception.cls.php 449 2011-11-13 13:07:48Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Image exception thrown by DOMPDF
12
+ *
13
+ * @package dompdf
14
+ */
15
+ class DOMPDF_Image_Exception extends DOMPDF_Exception {
16
+
17
+ /**
18
+ * Class constructor
19
+ *
20
+ * @param string $message Error message
21
+ * @param int $code Error code
22
+ */
23
+ function __construct($message = null, $code = 0) {
24
+ parent::__construct($message, $code);
25
+ }
26
+
27
+ }
dompdf/include/file.skel ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author ...
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: file.skel 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
dompdf/include/fixed_positioner.cls.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: fixed_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Positions fixely positioned frames
13
+ */
14
+ class Fixed_Positioner extends Positioner {
15
+
16
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
17
+
18
+ function position() {
19
+
20
+ $frame = $this->_frame;
21
+ $style = $frame->get_original_style();
22
+ $root = $frame->get_root();
23
+ $initialcb = $root->get_containing_block();
24
+ $initialcb_style = $root->get_style();
25
+
26
+ $p = $frame->find_block_parent();
27
+ if ( $p ) {
28
+ $p->add_line();
29
+ }
30
+
31
+ // Compute the margins of the @page style
32
+ $margin_top = $initialcb_style->length_in_pt($initialcb_style->margin_top, $initialcb["h"]);
33
+ $margin_right = $initialcb_style->length_in_pt($initialcb_style->margin_right, $initialcb["w"]);
34
+ $margin_bottom = $initialcb_style->length_in_pt($initialcb_style->margin_bottom, $initialcb["h"]);
35
+ $margin_left = $initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]);
36
+
37
+ // The needed computed style of the element
38
+ $height = $style->length_in_pt($style->height, $initialcb["h"]);
39
+ $width = $style->length_in_pt($style->width, $initialcb["w"]);
40
+
41
+ $top = $style->length_in_pt($style->top, $initialcb["h"]);
42
+ $right = $style->length_in_pt($style->right, $initialcb["w"]);
43
+ $bottom = $style->length_in_pt($style->bottom, $initialcb["h"]);
44
+ $left = $style->length_in_pt($style->left, $initialcb["w"]);
45
+
46
+ $y = $margin_top;
47
+ if ( isset($top) ) {
48
+ $y = $top + $margin_top;
49
+ if ( $top === "auto" ) {
50
+ $y = $margin_top;
51
+ if ( isset($bottom) && $bottom !== "auto" ) {
52
+ $y = $initialcb["h"] - $bottom - $margin_bottom;
53
+ $margin_height = $this->_frame->get_margin_height();
54
+ if ( $margin_height !== "auto" ) {
55
+ $y -= $margin_height;
56
+ } else {
57
+ $y -= $height;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ $x = $margin_left;
64
+ if ( isset($left) ) {
65
+ $x = $left + $margin_left;
66
+ if ( $left === "auto" ) {
67
+ $x = $margin_left;
68
+ if ( isset($right) && $right !== "auto" ) {
69
+ $x = $initialcb["w"] - $right - $margin_right;
70
+ $margin_width = $this->_frame->get_margin_width();
71
+ if ( $margin_width !== "auto" ) {
72
+ $x -= $margin_width;
73
+ } else {
74
+ $x -= $width;
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ $frame->set_position($x, $y);
81
+
82
+ $children = $frame->get_children();
83
+ foreach($children as $child) {
84
+ $child->set_position($x, $y);
85
+ }
86
+ }
87
+ }
dompdf/include/font_metrics.cls.php ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: font_metrics.cls.php 469 2012-02-05 22:25:30Z fabien.menager $
10
+ */
11
+
12
+ require_once DOMPDF_LIB_DIR . "/class.pdf.php";
13
+ require_once DOMPDF_LIB_DIR . "/php-font-lib/classes/font.cls.php";
14
+
15
+ /**
16
+ * Name of the font cache file
17
+ *
18
+ * This file must be writable by the webserver process only to update it
19
+ * with save_font_families() after adding the .afm file references of a new font family
20
+ * with Font_Metrics::save_font_families().
21
+ * This is typically done only from command line with load_font.php on converting
22
+ * ttf fonts to ufm with php-font-lib.
23
+ *
24
+ * Declared here because PHP5 prevents constants from being declared with expressions
25
+ */
26
+ if (!defined("__DOMPDF_FONT_CACHE_FILE")) {
27
+ if (file_exists(DOMPDF_FONT_DIR . "dompdf_font_family_cache")) {
28
+ define('__DOMPDF_FONT_CACHE_FILE', DOMPDF_FONT_DIR . "dompdf_font_family_cache");
29
+ } else {
30
+ define('__DOMPDF_FONT_CACHE_FILE', DOMPDF_FONT_DIR . "dompdf_font_family_cache.dist.php");
31
+ }
32
+ }
33
+
34
+ /**
35
+ * The font metrics class
36
+ *
37
+ * This class provides information about fonts and text. It can resolve
38
+ * font names into actual installed font files, as well as determine the
39
+ * size of text in a particular font and size.
40
+ *
41
+ * @static
42
+ * @package dompdf
43
+ */
44
+ class Font_Metrics {
45
+
46
+ /**
47
+ * @see __DOMPDF_FONT_CACHE_FILE
48
+ */
49
+ const CACHE_FILE = __DOMPDF_FONT_CACHE_FILE;
50
+
51
+ /**
52
+ * Underlying {@link Canvas} object to perform text size calculations
53
+ *
54
+ * @var Canvas
55
+ */
56
+ static protected $_pdf = null;
57
+
58
+ /**
59
+ * Array of font family names to font files
60
+ *
61
+ * Usually cached by the {@link load_font.php} script
62
+ *
63
+ * @var array
64
+ */
65
+ static protected $_font_lookup = array();
66
+
67
+
68
+ /**
69
+ * Class initialization
70
+ *
71
+ */
72
+ static function init(Canvas $canvas = null) {
73
+ if (!self::$_pdf) {
74
+ if (!$canvas) {
75
+ $canvas = Canvas_Factory::get_instance();
76
+ }
77
+
78
+ self::$_pdf = $canvas;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Calculates text size, in points
84
+ *
85
+ * @param string $text the text to be sized
86
+ * @param string $font the desired font
87
+ * @param float $size the desired font size
88
+ * @param float $spacing word spacing, if any
89
+ * @return float
90
+ */
91
+ static function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0) {
92
+ //return self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing);
93
+
94
+ // @todo Make sure this cache is efficient before enabling it
95
+ static $cache = array();
96
+
97
+ if ( $text === "" ) {
98
+ return 0;
99
+ }
100
+
101
+ // Don't cache long strings
102
+ $use_cache = !isset($text[50]); // Faster than strlen
103
+
104
+ $key = "$font/$size/$word_spacing/$char_spacing";
105
+
106
+ if ( $use_cache && isset($cache[$key][$text]) ) {
107
+ return $cache[$key]["$text"];
108
+ }
109
+
110
+ $width = self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing);
111
+
112
+ if ( $use_cache ) {
113
+ $cache[$key][$text] = $width;
114
+ }
115
+
116
+ return $width;
117
+ }
118
+
119
+ /**
120
+ * Calculates font height
121
+ *
122
+ * @param string $font
123
+ * @param float $size
124
+ * @return float
125
+ */
126
+ static function get_font_height($font, $size) {
127
+ return self::$_pdf->get_font_height($font, $size);
128
+ }
129
+
130
+ /**
131
+ * Resolves a font family & subtype into an actual font file
132
+ *
133
+ * Subtype can be one of 'normal', 'bold', 'italic' or 'bold_italic'. If
134
+ * the particular font family has no suitable font file, the default font
135
+ * ({@link DOMPDF_DEFAULT_FONT}) is used. The font file returned
136
+ * is the absolute pathname to the font file on the system.
137
+ *
138
+ * @param string $family
139
+ * @param string $subtype
140
+ * @return string
141
+ */
142
+ static function get_font($family, $subtype = "normal") {
143
+
144
+ /* Allow calling for various fonts in search path. Therefore not immediately
145
+ * return replacement on non match.
146
+ * Only when called with NULL try replacement.
147
+ * When this is also missing there is really trouble.
148
+ * If only the subtype fails, nevertheless return failure.
149
+ * Only on checking the fallback font, check various subtypes on same font.
150
+ */
151
+
152
+ if ( $family ) {
153
+ $family = str_replace( array("'", '"'), "", mb_strtolower($family));
154
+ $subtype = mb_strtolower($subtype);
155
+
156
+ if ( isset(self::$_font_lookup[$family][$subtype]) ) {
157
+ return self::$_font_lookup[$family][$subtype];
158
+ }
159
+ return null;
160
+ }
161
+
162
+ $family = DOMPDF_DEFAULT_FONT;
163
+
164
+ if ( isset(self::$_font_lookup[$family][$subtype]) ) {
165
+ return self::$_font_lookup[$family][$subtype];
166
+ }
167
+
168
+ foreach ( self::$_font_lookup[$family] as $sub => $font ) {
169
+ if (strpos($subtype, $sub) !== false) {
170
+ return $font;
171
+ }
172
+ }
173
+
174
+ if ($subtype !== "normal") {
175
+ foreach ( self::$_font_lookup[$family] as $sub => $font ) {
176
+ if ($sub !== "normal") {
177
+ return $font;
178
+ }
179
+ }
180
+ }
181
+
182
+ $subtype = "normal";
183
+
184
+ if ( isset(self::$_font_lookup[$family][$subtype]) ) {
185
+ return self::$_font_lookup[$family][$subtype];
186
+ }
187
+ return null;
188
+ }
189
+
190
+ static function get_family($family) {
191
+ $family = str_replace( array("'", '"'), "", mb_strtolower($family));
192
+
193
+ if ( isset(self::$_font_lookup[$family]) ) {
194
+ return self::$_font_lookup[$family];
195
+ }
196
+
197
+ return null;
198
+ }
199
+
200
+ /**
201
+ * Saves the stored font family cache
202
+ *
203
+ * The name and location of the cache file are determined by {@link
204
+ * Font_Metrics::CACHE_FILE}. This file should be writable by the
205
+ * webserver process.
206
+ *
207
+ * @see Font_Metrics::load_font_families()
208
+ */
209
+ static function save_font_families() {
210
+ // replace the path to the DOMPDF font directory with "DOMPDF_FONT_DIR" (allows for more portability)
211
+ $cache_data = var_export(self::$_font_lookup, true);
212
+ $cache_data = str_replace('\''.DOMPDF_FONT_DIR , 'DOMPDF_FONT_DIR . \'' , $cache_data);
213
+ $cache_data = "<"."?php return $cache_data ?".">";
214
+ file_put_contents(self::CACHE_FILE, $cache_data);
215
+ }
216
+
217
+ /**
218
+ * Loads the stored font family cache
219
+ *
220
+ * @see save_font_families()
221
+ */
222
+ static function load_font_families() {
223
+ if ( !is_readable(self::CACHE_FILE) )
224
+ return;
225
+
226
+ self::$_font_lookup = require_once(self::CACHE_FILE);
227
+
228
+ // If the font family cache is still in the old format
229
+ if ( self::$_font_lookup === 1 ) {
230
+ $cache_data = file_get_contents(self::CACHE_FILE);
231
+ file_put_contents(self::CACHE_FILE, "<"."?php return $cache_data ?".">");
232
+ self::$_font_lookup = require_once(self::CACHE_FILE);
233
+ }
234
+ }
235
+
236
+ static function get_type($type) {
237
+ if (preg_match("/bold/i", $type)) {
238
+ if (preg_match("/italic|oblique/i", $type)) {
239
+ $type = "bold_italic";
240
+ }
241
+ else {
242
+ $type = "bold";
243
+ }
244
+ }
245
+ elseif (preg_match("/italic|oblique/i", $type)) {
246
+ $type = "italic";
247
+ }
248
+ else {
249
+ $type = "normal";
250
+ }
251
+
252
+ return $type;
253
+ }
254
+
255
+ static function install_fonts($files) {
256
+ $names = array();
257
+
258
+ foreach($files as $file) {
259
+ $font = Font::load($file);
260
+ $records = $font->getData("name", "records");
261
+ $type = self::get_type($records[2]);
262
+ $names[mb_strtolower($records[1])][$type] = $file;
263
+ }
264
+
265
+ return $names;
266
+ }
267
+
268
+ static function get_system_fonts() {
269
+ $files = glob("/usr/share/fonts/truetype/*.ttf") +
270
+ glob("/usr/share/fonts/truetype/*/*.ttf") +
271
+ glob("/usr/share/fonts/truetype/*/*/*.ttf") +
272
+ glob("C:\\Windows\\fonts\\*.ttf") +
273
+ glob("C:\\WinNT\\fonts\\*.ttf") +
274
+ glob("/mnt/c_drive/WINDOWS/Fonts/");
275
+
276
+ return self::install_fonts($files);
277
+ }
278
+
279
+ /**
280
+ * Returns the current font lookup table
281
+ *
282
+ * @return array
283
+ */
284
+ static function get_font_families() {
285
+ return self::$_font_lookup;
286
+ }
287
+
288
+ static function set_font_family($fontname, $entry) {
289
+ self::$_font_lookup[mb_strtolower($fontname)] = $entry;
290
+ }
291
+
292
+ static function register_font($style, $remote_file) {
293
+ $fontname = mb_strtolower($style["family"]);
294
+ $families = Font_Metrics::get_font_families();
295
+
296
+ $entry = array();
297
+ if ( isset($families[$fontname]) ) {
298
+ $entry = $families[$fontname];
299
+ }
300
+
301
+ $remote_file = $remote_file;
302
+ $local_file = DOMPDF_FONT_DIR . md5($remote_file);
303
+ $cache_entry = $local_file;
304
+ $local_file .= ".ttf";
305
+
306
+ $style_string = Font_Metrics::get_type("{$style['weight']} {$style['style']}");
307
+
308
+ if ( !isset($entry[$style_string]) ) {
309
+ $entry[$style_string] = $cache_entry;
310
+
311
+ Font_Metrics::set_font_family($fontname, $entry);
312
+
313
+ // Download the remote file
314
+ if ( !is_file($local_file) ) {
315
+ file_put_contents($local_file, file_get_contents($remote_file));
316
+ }
317
+
318
+ $font = Font::load($local_file);
319
+
320
+ if (!$font) {
321
+ return false;
322
+ }
323
+
324
+ $font->parse();
325
+ $font->saveAdobeFontMetrics("$cache_entry.ufm");
326
+
327
+ // Save the changes
328
+ Font_Metrics::save_font_families();
329
+ }
330
+
331
+ return true;
332
+ }
333
+ }
334
+
335
+ Font_Metrics::load_font_families();
dompdf/include/frame.cls.php ADDED
@@ -0,0 +1,1113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: frame.cls.php 450 2012-01-10 22:29:32Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * The main Frame class
12
+ *
13
+ * This class represents a single HTML element. This class stores
14
+ * positioning information as well as containing block location and
15
+ * dimensions. Style information for the element is stored in a {@link
16
+ * Style} object. Tree structure is maintained via the parent & children
17
+ * links.
18
+ *
19
+ * @access protected
20
+ * @package dompdf
21
+ */
22
+ class Frame {
23
+
24
+ /**
25
+ * The DOMNode object this frame represents
26
+ *
27
+ * @var DOMNode
28
+ */
29
+ protected $_node;
30
+
31
+ /**
32
+ * Unique identifier for this frame. Used to reference this frame
33
+ * via the node.
34
+ *
35
+ * @var string
36
+ */
37
+ protected $_id;
38
+
39
+ /**
40
+ * Unique id counter
41
+ */
42
+ static /*protected*/ $ID_COUNTER = 0;
43
+
44
+ /**
45
+ * This frame's calculated style
46
+ *
47
+ * @var Style
48
+ */
49
+ protected $_style;
50
+
51
+ /**
52
+ * This frame's original style. Needed for cases where frames are
53
+ * split across pages.
54
+ *
55
+ * @var Style
56
+ */
57
+ protected $_original_style;
58
+
59
+ /**
60
+ * This frame's parent in the document tree.
61
+ *
62
+ * @var Frame
63
+ */
64
+ protected $_parent;
65
+
66
+ /**
67
+ * This frame's children
68
+ *
69
+ * @var array
70
+ */
71
+ protected $_frame_list;
72
+
73
+ /**
74
+ * This frame's first child. All children are handled as a
75
+ * doubly-linked list.
76
+ *
77
+ * @var Frame
78
+ */
79
+ protected $_first_child;
80
+
81
+ /**
82
+ * This frame's last child.
83
+ *
84
+ * @var Frame
85
+ */
86
+ protected $_last_child;
87
+
88
+ /**
89
+ * This frame's previous sibling in the document tree.
90
+ *
91
+ * @var Frame
92
+ */
93
+ protected $_prev_sibling;
94
+
95
+ /**
96
+ * This frame's next sibling in the document tree.
97
+ *
98
+ * @var Frame
99
+ */
100
+ protected $_next_sibling;
101
+
102
+ /**
103
+ * This frame's containing block (used in layout): array(x, y, w, h)
104
+ *
105
+ * @var array
106
+ */
107
+ protected $_containing_block;
108
+
109
+ /**
110
+ * Position on the page of the top-left corner of the margin box of
111
+ * this frame: array(x,y)
112
+ *
113
+ * @var array
114
+ */
115
+ protected $_position;
116
+
117
+ /**
118
+ * Absolute opacity of this frame
119
+ *
120
+ * @var float
121
+ */
122
+ protected $_opacity;
123
+
124
+ /**
125
+ * This frame's decorator
126
+ *
127
+ * @var Frame_Decorator
128
+ */
129
+ protected $_decorator;
130
+
131
+ /**
132
+ * This frame's containing line box
133
+ * @var Line_Box
134
+ */
135
+ protected $_containing_line;
136
+
137
+ protected $_is_cache = array();
138
+
139
+ /**
140
+ * Tells wether the frame was already pushed to the next page
141
+ * @var bool
142
+ */
143
+ public $_already_pushed = false;
144
+
145
+ public $_float_next_line = false;
146
+
147
+ static $_ws_state = self::WS_SPACE;
148
+
149
+ const WS_TEXT = 1;
150
+ const WS_SPACE = 2;
151
+
152
+ /**
153
+ * Class destructor
154
+ */
155
+ function __destruct() {
156
+ clear_object($this);
157
+ }
158
+
159
+ /**
160
+ * Class constructor
161
+ *
162
+ * @param DOMNode $node the DOMNode this frame represents
163
+ */
164
+ function __construct(DOMNode $node) {
165
+ $this->_node = $node;
166
+
167
+ $this->_parent = null;
168
+ $this->_first_child = null;
169
+ $this->_last_child = null;
170
+ $this->_prev_sibling = $this->_next_sibling = null;
171
+
172
+ $this->_style = null;
173
+ $this->_original_style = null;
174
+
175
+ $this->_containing_block = array(
176
+ "x" => null,
177
+ "y" => null,
178
+ "w" => null,
179
+ "h" => null,
180
+ );
181
+
182
+ $this->_containing_block[0] =& $this->_containing_block["x"];
183
+ $this->_containing_block[1] =& $this->_containing_block["y"];
184
+ $this->_containing_block[2] =& $this->_containing_block["w"];
185
+ $this->_containing_block[3] =& $this->_containing_block["h"];
186
+
187
+ $this->_position = array(
188
+ "x" => null,
189
+ "y" => null,
190
+ );
191
+
192
+ $this->_position[0] =& $this->_position["x"];
193
+ $this->_position[1] =& $this->_position["y"];
194
+
195
+ $this->_opacity = 1.0;
196
+ $this->_decorator = null;
197
+
198
+ $this->set_id( self::$ID_COUNTER++ );
199
+ }
200
+
201
+ // WIP : preprocessing to remove all the unused whitespace
202
+ protected function ws_trim(){
203
+ if ( $this->ws_keep() ) return;
204
+
205
+ switch(self::$_ws_state) {
206
+ case self::WS_SPACE:
207
+ $node = $this->_node;
208
+
209
+ if ( $node->nodeName === "#text" ) {
210
+ $node->data = preg_replace("/[ \t\r\n\f]+/u", " ", $text);
211
+
212
+ // starts with a whitespace
213
+ if ( isset($node->data[0]) && $node->data[0] === " " ) {
214
+ $node->data = ltrim($node->data);
215
+ }
216
+
217
+ // if not empty
218
+ if ( $node->data !== "" ) {
219
+ // change the current state (text)
220
+ self::$_ws_state = self::WS_TEXT;
221
+
222
+ // ends with a whitespace
223
+ if ( preg_match("/[ \t\r\n\f]+$/u", $node->data) ) {
224
+ $node->data = ltrim($node->data);
225
+ }
226
+ }
227
+ }
228
+ break;
229
+
230
+ case self::WS_TEXT:
231
+ }
232
+ }
233
+
234
+ protected function ws_keep(){
235
+ $whitespace = $this->get_style()->white_space;
236
+ return in_array($whitespace, array("pre", "pre-wrap", "pre-line"));
237
+ }
238
+
239
+ protected function ws_is_text(){
240
+ $node = $this->get_node();
241
+
242
+ if ($node->nodeName === "img") {
243
+ return true;
244
+ }
245
+
246
+ if ( !$this->is_in_flow() ) {
247
+ return false;
248
+ }
249
+
250
+ if ($this->is_text_node()) {
251
+ return trim($node->nodeValue) !== "";
252
+ }
253
+
254
+ return true;
255
+ }
256
+
257
+ /**
258
+ * "Destructor": forcibly free all references held by this frame
259
+ *
260
+ * @param bool $recursive if true, call dispose on all children
261
+ */
262
+ function dispose($recursive = false) {
263
+
264
+ if ( $recursive ) {
265
+ while ( $child = $this->_first_child )
266
+ $child->dispose(true);
267
+ }
268
+
269
+ // Remove this frame from the tree
270
+ if ( $this->_prev_sibling ) {
271
+ $this->_prev_sibling->_next_sibling = $this->_next_sibling;
272
+ }
273
+
274
+ if ( $this->_next_sibling ) {
275
+ $this->_next_sibling->_prev_sibling = $this->_prev_sibling;
276
+ }
277
+
278
+ if ( $this->_parent && $this->_parent->_first_child === $this ) {
279
+ $this->_parent->_first_child = $this->_next_sibling;
280
+ }
281
+
282
+ if ( $this->_parent && $this->_parent->_last_child === $this ) {
283
+ $this->_parent->_last_child = $this->_prev_sibling;
284
+ }
285
+
286
+ if ( $this->_parent ) {
287
+ $this->_parent->get_node()->removeChild($this->_node);
288
+ }
289
+
290
+ $this->_style->dispose();
291
+ $this->_style = null;
292
+ unset($this->_style);
293
+
294
+ $this->_original_style->dispose();
295
+ $this->_original_style = null;
296
+ unset($this->_original_style);
297
+
298
+ }
299
+
300
+ // Re-initialize the frame
301
+ function reset() {
302
+ $this->_position["x"] = null;
303
+ $this->_position["y"] = null;
304
+
305
+ $this->_containing_block["x"] = null;
306
+ $this->_containing_block["y"] = null;
307
+ $this->_containing_block["w"] = null;
308
+ $this->_containing_block["h"] = null;
309
+
310
+ $this->_style = null;
311
+ unset($this->_style);
312
+ $this->_style = clone $this->_original_style;
313
+ }
314
+
315
+ //........................................................................
316
+
317
+ // Accessor methods
318
+ /**
319
+ * @return DOMNode
320
+ */
321
+ function get_node() { return $this->_node; }
322
+
323
+ /**
324
+ * @return string
325
+ */
326
+ function get_id() { return $this->_id; }
327
+
328
+ /**
329
+ * @return Style
330
+ */
331
+ function get_style() { return $this->_style; }
332
+
333
+ /**
334
+ * @return Style
335
+ */
336
+ function get_original_style() { return $this->_original_style; }
337
+
338
+ /**
339
+ * @return Frame
340
+ */
341
+ function get_parent() { return $this->_parent; }
342
+
343
+ /**
344
+ * @return Frame_Decorator
345
+ */
346
+ function get_decorator() { return $this->_decorator; }
347
+
348
+ /**
349
+ * @return Frame
350
+ */
351
+ function get_first_child() { return $this->_first_child; }
352
+
353
+ /**
354
+ * @return Frame
355
+ */
356
+ function get_last_child() { return $this->_last_child; }
357
+
358
+ /**
359
+ * @return Frame
360
+ */
361
+ function get_prev_sibling() { return $this->_prev_sibling; }
362
+
363
+ /**
364
+ * @return Frame
365
+ */
366
+ function get_next_sibling() { return $this->_next_sibling; }
367
+
368
+ /**
369
+ * @return FrameList
370
+ */
371
+ function get_children() {
372
+ if ( isset($this->_frame_list) ) {
373
+ return $this->_frame_list;
374
+ }
375
+
376
+ $this->_frame_list = new FrameList($this);
377
+ return $this->_frame_list;
378
+ }
379
+
380
+ // Layout property accessors
381
+
382
+ /**
383
+ * Containing block dimensions
384
+ *
385
+ * @param $i string The key of the wanted containing block's dimension (x, y, x, h)
386
+ * @return array|float
387
+ */
388
+ function get_containing_block($i = null) {
389
+ if ( isset($i) ) {
390
+ return $this->_containing_block[$i];
391
+ }
392
+ return $this->_containing_block;
393
+ }
394
+
395
+ /**
396
+ * Block position
397
+ *
398
+ * @param $i string The key of the wanted position value (x, y)
399
+ * @return array|float
400
+ */
401
+ function get_position($i = null) {
402
+ if ( isset($i) ) {
403
+ return $this->_position[$i];
404
+ }
405
+ return $this->_position;
406
+ }
407
+
408
+ //........................................................................
409
+
410
+ /**
411
+ * Return the height of the margin box of the frame, in pt. Meaningless
412
+ * unless the height has been calculated properly.
413
+ *
414
+ * @return float
415
+ */
416
+ function get_margin_height() {
417
+ $style = $this->_style;
418
+
419
+ return $style->length_in_pt(array(
420
+ $style->height,
421
+ $style->margin_top,
422
+ $style->margin_bottom,
423
+ $style->border_top_width,
424
+ $style->border_bottom_width,
425
+ $style->padding_top,
426
+ $style->padding_bottom
427
+ ), $this->_containing_block["h"]);
428
+ }
429
+
430
+ /**
431
+ * Return the width of the margin box of the frame, in pt. Meaningless
432
+ * unless the width has been calculated properly.
433
+ *
434
+ * @return float
435
+ */
436
+ function get_margin_width() {
437
+ $style = $this->_style;
438
+
439
+ return $style->length_in_pt(array(
440
+ $style->width,
441
+ $style->margin_left,
442
+ $style->margin_right,
443
+ $style->border_left_width,
444
+ $style->border_right_width,
445
+ $style->padding_left,
446
+ $style->padding_right
447
+ ), $this->_containing_block["w"]);
448
+ }
449
+
450
+ function get_break_margins(){
451
+ $style = $this->_style;
452
+
453
+ return $style->length_in_pt(array(
454
+ //$style->height,
455
+ $style->margin_top,
456
+ $style->margin_bottom,
457
+ $style->border_top_width,
458
+ $style->border_bottom_width,
459
+ $style->padding_top,
460
+ $style->padding_bottom
461
+ ), $this->_containing_block["h"]);
462
+ }
463
+
464
+ /**
465
+ * Return the padding box (x,y,w,h) of the frame
466
+ *
467
+ * @return array
468
+ */
469
+ function get_padding_box() {
470
+ $style = $this->_style;
471
+ $cb = $this->_containing_block;
472
+
473
+ $x = $this->_position["x"] +
474
+ $style->length_in_pt(array($style->margin_left,
475
+ $style->border_left_width),
476
+ $cb["w"]);
477
+
478
+ $y = $this->_position["y"] +
479
+ $style->length_in_pt(array($style->margin_top,
480
+ $style->border_top_width),
481
+ $cb["h"]);
482
+
483
+ $w = $style->length_in_pt(array($style->padding_left,
484
+ $style->width,
485
+ $style->padding_right),
486
+ $cb["w"]);
487
+
488
+ $h = $style->length_in_pt(array($style->padding_top,
489
+ $style->height,
490
+ $style->padding_bottom),
491
+ $cb["h"]);
492
+
493
+ return array(0 => $x, "x" => $x,
494
+ 1 => $y, "y" => $y,
495
+ 2 => $w, "w" => $w,
496
+ 3 => $h, "h" => $h);
497
+ }
498
+
499
+ /**
500
+ * Return the border box of the frame
501
+ *
502
+ * @return array
503
+ */
504
+ function get_border_box() {
505
+ $style = $this->_style;
506
+ $cb = $this->_containing_block;
507
+
508
+ $x = $this->_position["x"] + $style->length_in_pt($style->margin_left, $cb["w"]);
509
+
510
+ $y = $this->_position["y"] + $style->length_in_pt($style->margin_top, $cb["h"]);
511
+
512
+ $w = $style->length_in_pt(array($style->border_left_width,
513
+ $style->padding_left,
514
+ $style->width,
515
+ $style->padding_right,
516
+ $style->border_right_width),
517
+ $cb["w"]);
518
+
519
+ $h = $style->length_in_pt(array($style->border_top_width,
520
+ $style->padding_top,
521
+ $style->height,
522
+ $style->padding_bottom,
523
+ $style->border_bottom_width),
524
+ $cb["h"]);
525
+
526
+ return array(0 => $x, "x" => $x,
527
+ 1 => $y, "y" => $y,
528
+ 2 => $w, "w" => $w,
529
+ 3 => $h, "h" => $h);
530
+ }
531
+
532
+ function get_opacity($opacity = null) {
533
+ if ( $opacity !== null ) {
534
+ $this->set_opacity($opacity);
535
+ }
536
+ return $this->_opacity;
537
+ }
538
+
539
+ /**
540
+ * @return Line_Box
541
+ */
542
+ function &get_containing_line() {
543
+ return $this->_containing_line;
544
+ }
545
+
546
+ //........................................................................
547
+
548
+ // Set methods
549
+ function set_id($id) {
550
+ $this->_id = $id;
551
+
552
+ // We can only set attributes of DOMElement objects (nodeType == 1).
553
+ // Since these are the only objects that we can assign CSS rules to,
554
+ // this shortcoming is okay.
555
+ if ( $this->_node->nodeType == XML_ELEMENT_NODE )
556
+ $this->_node->setAttribute("frame_id", $id);
557
+ }
558
+
559
+ function set_style(Style $style) {
560
+ if ( is_null($this->_style) )
561
+ $this->_original_style = clone $style;
562
+
563
+ //$style->set_frame($this);
564
+ $this->_style = $style;
565
+ }
566
+
567
+ function set_decorator(Frame_Decorator $decorator) {
568
+ $this->_decorator = $decorator;
569
+ }
570
+
571
+ function set_containing_block($x = null, $y = null, $w = null, $h = null) {
572
+ if ( is_array($x) ){
573
+ foreach($x as $key => $val){
574
+ $$key = $val;
575
+ }
576
+ }
577
+
578
+ if (is_numeric($x)) {
579
+ $this->_containing_block["x"] = $x;
580
+ }
581
+
582
+ if (is_numeric($y)) {
583
+ $this->_containing_block["y"] = $y;
584
+ }
585
+
586
+ if (is_numeric($w)) {
587
+ $this->_containing_block["w"] = $w;
588
+ }
589
+
590
+ if (is_numeric($h)) {
591
+ $this->_containing_block["h"] = $h;
592
+ }
593
+ }
594
+
595
+ function set_position($x = null, $y = null) {
596
+ if ( is_array($x) )
597
+ extract($x);
598
+
599
+ if ( is_numeric($x) ) {
600
+ $this->_position["x"] = $x;
601
+ }
602
+
603
+ if ( is_numeric($y) ) {
604
+ $this->_position["y"] = $y;
605
+ }
606
+ }
607
+
608
+ function set_opacity($opacity) {
609
+ $parent = $this->get_parent();
610
+ $base_opacity = (($parent && $parent->_opacity !== null) ? $parent->_opacity : 1.0);
611
+ $this->_opacity = $base_opacity * $opacity;
612
+ }
613
+
614
+ function set_containing_line(Line_Box $line) {
615
+ $this->_containing_line = $line;
616
+ }
617
+
618
+ //........................................................................
619
+
620
+ /**
621
+ * Tells if the frame is a text node
622
+ * @return bool
623
+ */
624
+ function is_text_node() {
625
+ if ( isset($this->_is_cache["text_node"]) ) {
626
+ return $this->_is_cache["text_node"];
627
+ }
628
+
629
+ return $this->_is_cache["text_node"] = ($this->get_node()->nodeName === "#text");
630
+ }
631
+
632
+ function is_positionned() {
633
+ if ( isset($this->_is_cache["positionned"]) ) {
634
+ return $this->_is_cache["positionned"];
635
+ }
636
+
637
+ $position = $this->get_style()->position;
638
+
639
+ return $this->_is_cache["positionned"] = in_array($position, Style::$POSITIONNED_TYPES);
640
+ }
641
+
642
+ function is_absolute() {
643
+ if ( isset($this->_is_cache["absolute"]) ) {
644
+ return $this->_is_cache["absolute"];
645
+ }
646
+
647
+ $position = $this->get_style()->position;
648
+
649
+ return $this->_is_cache["absolute"] = ($position === "absolute" || $position === "fixed");
650
+ }
651
+
652
+ function is_block() {
653
+ if ( isset($this->_is_cache["block"]) ) {
654
+ return $this->_is_cache["block"];
655
+ }
656
+
657
+ return $this->_is_cache["block"] = in_array($this->get_style()->display, Style::$BLOCK_TYPES);
658
+ }
659
+
660
+ function is_in_flow() {
661
+ if ( isset($this->_is_cache["in_flow"]) ) {
662
+ return $this->_is_cache["in_flow"];
663
+ }
664
+
665
+ return $this->_is_cache["in_flow"] = !(DOMPDF_ENABLE_CSS_FLOAT && $this->get_style()->float !== "none" || $this->is_absolute());
666
+ }
667
+
668
+ function is_pre(){
669
+ if ( isset($this->_is_cache["pre"]) ) {
670
+ return $this->_is_cache["pre"];
671
+ }
672
+
673
+ $white_space = $this->get_style()->white_space;
674
+
675
+ return $this->_is_cache["pre"] = in_array($white_space, array("pre", "pre-wrap"));
676
+ }
677
+
678
+ function is_table(){
679
+ if ( isset($this->_is_cache["table"]) ) {
680
+ return $this->_is_cache["table"];
681
+ }
682
+
683
+ $display = $this->get_style()->display;
684
+
685
+ return $this->_is_cache["table"] = in_array($display, Style::$TABLE_TYPES);
686
+ }
687
+
688
+
689
+ /**
690
+ * Inserts a new child at the beginning of the Frame
691
+ *
692
+ * @param $child Frame The new Frame to insert
693
+ * @param $update_node boolean Whether or not to update the DOM
694
+ */
695
+ function prepend_child(Frame $child, $update_node = true) {
696
+ if ( $update_node )
697
+ $this->_node->insertBefore($child->_node, $this->_first_child ? $this->_first_child->_node : null);
698
+
699
+ // Remove the child from its parent
700
+ if ( $child->_parent )
701
+ $child->_parent->remove_child($child, false);
702
+
703
+ $child->_parent = $this;
704
+ $child->_prev_sibling = null;
705
+
706
+ // Handle the first child
707
+ if ( !$this->_first_child ) {
708
+ $this->_first_child = $child;
709
+ $this->_last_child = $child;
710
+ $child->_next_sibling = null;
711
+ } else {
712
+ $this->_first_child->_prev_sibling = $child;
713
+ $child->_next_sibling = $this->_first_child;
714
+ $this->_first_child = $child;
715
+ }
716
+ }
717
+
718
+ /**
719
+ * Inserts a new child at the end of the Frame
720
+ *
721
+ * @param $child Frame The new Frame to insert
722
+ * @param $update_node boolean Whether or not to update the DOM
723
+ */
724
+ function append_child(Frame $child, $update_node = true) {
725
+ if ( $update_node )
726
+ $this->_node->appendChild($child->_node);
727
+
728
+ // Remove the child from its parent
729
+ if ( $child->_parent )
730
+ $child->_parent->remove_child($child, false);
731
+
732
+ $child->_parent = $this;
733
+ $child->_next_sibling = null;
734
+
735
+ // Handle the first child
736
+ if ( !$this->_last_child ) {
737
+ $this->_first_child = $child;
738
+ $this->_last_child = $child;
739
+ $child->_prev_sibling = null;
740
+ } else {
741
+ $this->_last_child->_next_sibling = $child;
742
+ $child->_prev_sibling = $this->_last_child;
743
+ $this->_last_child = $child;
744
+ }
745
+ }
746
+
747
+ /**
748
+ * Inserts a new child immediately before the specified frame
749
+ *
750
+ * @param $new_child Frame The new Frame to insert
751
+ * @param $ref Frame The Frame after the new Frame
752
+ * @param $update_node boolean Whether or not to update the DOM
753
+ */
754
+ function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) {
755
+ if ( $ref === $this->_first_child ) {
756
+ $this->prepend_child($new_child, $update_node);
757
+ return;
758
+ }
759
+
760
+ if ( is_null($ref) ) {
761
+ $this->append_child($new_child, $update_node);
762
+ return;
763
+ }
764
+
765
+ if ( $ref->_parent !== $this )
766
+ throw new DOMPDF_Exception("Reference child is not a child of this node.");
767
+
768
+ // Update the node
769
+ if ( $update_node )
770
+ $this->_node->insertBefore($new_child->_node, $ref->_node);
771
+
772
+ // Remove the child from its parent
773
+ if ( $new_child->_parent )
774
+ $new_child->_parent->remove_child($new_child, false);
775
+
776
+ $new_child->_parent = $this;
777
+ $new_child->_next_sibling = $ref;
778
+ $new_child->_prev_sibling = $ref->_prev_sibling;
779
+
780
+ if ( $ref->_prev_sibling )
781
+ $ref->_prev_sibling->_next_sibling = $new_child;
782
+
783
+ $ref->_prev_sibling = $new_child;
784
+ }
785
+
786
+ /**
787
+ * Inserts a new child immediately after the specified frame
788
+ *
789
+ * @param $new_child Frame The new Frame to insert
790
+ * @param $ref Frame The Frame before the new Frame
791
+ * @param $update_node boolean Whether or not to update the DOM
792
+ */
793
+ function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) {
794
+ if ( $ref === $this->_last_child ) {
795
+ $this->append_child($new_child, $update_node);
796
+ return;
797
+ }
798
+
799
+ if ( is_null($ref) ) {
800
+ $this->prepend_child($new_child, $update_node);
801
+ return;
802
+ }
803
+
804
+ if ( $ref->_parent !== $this )
805
+ throw new DOMPDF_Exception("Reference child is not a child of this node.");
806
+
807
+ // Update the node
808
+ if ( $update_node ) {
809
+ if ( $ref->_next_sibling ) {
810
+ $next_node = $ref->_next_sibling->_node;
811
+ $this->_node->insertBefore($new_child->_node, $next_node);
812
+ } else {
813
+ $new_child->_node = $this->_node->appendChild($new_child);
814
+ }
815
+ }
816
+
817
+ // Remove the child from its parent
818
+ if ( $new_child->_parent)
819
+ $new_child->_parent->remove_child($new_child, false);
820
+
821
+ $new_child->_parent = $this;
822
+ $new_child->_prev_sibling = $ref;
823
+ $new_child->_next_sibling = $ref->_next_sibling;
824
+
825
+ if ( $ref->_next_sibling )
826
+ $ref->_next_sibling->_prev_sibling = $new_child;
827
+
828
+ $ref->_next_sibling = $new_child;
829
+ }
830
+
831
+
832
+ /**
833
+ * Remove a child frame
834
+ *
835
+ * @param $child Frame
836
+ * @param $update_node boolean Whether or not to remove the DOM node
837
+ * @return Frame The removed child frame
838
+ */
839
+ function remove_child(Frame $child, $update_node = true) {
840
+ if ( $child->_parent !== $this )
841
+ throw new DOMPDF_Exception("Child not found in this frame");
842
+
843
+ if ( $update_node )
844
+ $this->_node->removeChild($child->_node);
845
+
846
+ if ( $child === $this->_first_child )
847
+ $this->_first_child = $child->_next_sibling;
848
+
849
+ if ( $child === $this->_last_child )
850
+ $this->_last_child = $child->_prev_sibling;
851
+
852
+ if ( $child->_prev_sibling )
853
+ $child->_prev_sibling->_next_sibling = $child->_next_sibling;
854
+
855
+ if ( $child->_next_sibling )
856
+ $child->_next_sibling->_prev_sibling = $child->_prev_sibling;
857
+
858
+ $child->_next_sibling = null;
859
+ $child->_prev_sibling = null;
860
+ $child->_parent = null;
861
+ return $child;
862
+ }
863
+
864
+ //........................................................................
865
+
866
+ // Debugging function:
867
+ function __toString() {
868
+ // Skip empty text frames
869
+ // if ( $this->is_text_node() &&
870
+ // preg_replace("/\s/", "", $this->_node->data) === "" )
871
+ // return "";
872
+
873
+
874
+ $str = "<b>" . $this->_node->nodeName . ":</b><br/>";
875
+ //$str .= spl_object_hash($this->_node) . "<br/>";
876
+ $str .= "Id: " .$this->get_id() . "<br/>";
877
+ $str .= "Class: " .get_class($this) . "<br/>";
878
+
879
+ if ( $this->is_text_node() ) {
880
+ $tmp = htmlspecialchars($this->_node->nodeValue);
881
+ $str .= "<pre>'" . mb_substr($tmp,0,70) .
882
+ (mb_strlen($tmp) > 70 ? "..." : "") . "'</pre>";
883
+ } elseif ( $css_class = $this->_node->getAttribute("class") ) {
884
+ $tmp = htmlspecialchars($css_class);
885
+ $str .= "CSS class: '$css_class'<br/>";
886
+ }
887
+
888
+ if ( $this->_parent )
889
+ $str .= "\nParent:" . $this->_parent->_node->nodeName .
890
+ " (" . spl_object_hash($this->_parent->_node) . ") " .
891
+ "<br/>";
892
+
893
+ if ( $this->_prev_sibling )
894
+ $str .= "Prev: " . $this->_prev_sibling->_node->nodeName .
895
+ " (" . spl_object_hash($this->_prev_sibling->_node) . ") " .
896
+ "<br/>";
897
+
898
+ if ( $this->_next_sibling )
899
+ $str .= "Next: " . $this->_next_sibling->_node->nodeName .
900
+ " (" . spl_object_hash($this->_next_sibling->_node) . ") " .
901
+ "<br/>";
902
+
903
+ $d = $this->get_decorator();
904
+ while ($d && $d != $d->get_decorator()) {
905
+ $str .= "Decorator: " . get_class($d) . "<br/>";
906
+ $d = $d->get_decorator();
907
+ }
908
+
909
+ $str .= "Position: " . pre_r($this->_position, true);
910
+ $str .= "\nContaining block: " . pre_r($this->_containing_block, true);
911
+ $str .= "\nMargin width: " . pre_r($this->get_margin_width(), true);
912
+ $str .= "\nMargin height: " . pre_r($this->get_margin_height(), true);
913
+
914
+ $str .= "\nStyle: <pre>". $this->_style->__toString() . "</pre>";
915
+
916
+ if ( $this->_decorator instanceof Block_Frame_Decorator ) {
917
+ $str .= "Lines:<pre>";
918
+ foreach ($this->_decorator->get_line_boxes() as $line) {
919
+ foreach ($line->get_frames() as $frame) {
920
+ if ($frame instanceof Text_Frame_Decorator) {
921
+ $str .= "\ntext: ";
922
+ $str .= "'". htmlspecialchars($frame->get_text()) ."'";
923
+ } else {
924
+ $str .= "\nBlock: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")";
925
+ }
926
+ }
927
+
928
+ $str .=
929
+ "\ny => " . $line->y . "\n" .
930
+ "w => " . $line->w . "\n" .
931
+ "h => " . $line->h . "\n" .
932
+ "left => " . $line->left . "\n" .
933
+ "right => " . $line->right . "\n";
934
+ }
935
+ $str .= "</pre>";
936
+ }
937
+ $str .= "\n";
938
+ if ( php_sapi_name() === "cli" )
939
+ $str = strip_tags(str_replace(array("<br/>","<b>","</b>"),
940
+ array("\n","",""),
941
+ $str));
942
+
943
+ return $str;
944
+ }
945
+ }
946
+
947
+ //------------------------------------------------------------------------
948
+
949
+ /**
950
+ * Linked-list IteratorAggregate
951
+ *
952
+ * @access private
953
+ * @package dompdf
954
+ */
955
+ class FrameList implements IteratorAggregate {
956
+ protected $_frame;
957
+
958
+ function __construct($frame) { $this->_frame = $frame; }
959
+ function getIterator() { return new FrameListIterator($this->_frame); }
960
+ }
961
+
962
+ /**
963
+ * Linked-list Iterator
964
+ *
965
+ * Returns children in order and allows for list to change during iteration,
966
+ * provided the changes occur to or after the current element
967
+ *
968
+ * @access private
969
+ * @package dompdf
970
+ */
971
+ class FrameListIterator implements Iterator {
972
+
973
+ /**
974
+ * @var Frame
975
+ */
976
+ protected $_parent;
977
+
978
+ /**
979
+ * @var Frame
980
+ */
981
+ protected $_cur;
982
+
983
+ /**
984
+ * @var int
985
+ */
986
+ protected $_num;
987
+
988
+ function __construct(Frame $frame) {
989
+ $this->_parent = $frame;
990
+ $this->_cur = $frame->get_first_child();
991
+ $this->_num = 0;
992
+ }
993
+
994
+ function rewind() {
995
+ $this->_cur = $this->_parent->get_first_child();
996
+ $this->_num = 0;
997
+ }
998
+
999
+ /**
1000
+ * @return bool
1001
+ */
1002
+ function valid() {
1003
+ return isset($this->_cur);// && ($this->_cur->get_prev_sibling() === $this->_prev);
1004
+ }
1005
+
1006
+ function key() { return $this->_num; }
1007
+
1008
+ /**
1009
+ * @return Frame
1010
+ */
1011
+ function current() { return $this->_cur; }
1012
+
1013
+ /**
1014
+ * @return Frame
1015
+ */
1016
+ function next() {
1017
+
1018
+ $ret = $this->_cur;
1019
+ if ( !$ret )
1020
+ return null;
1021
+
1022
+ $this->_cur = $this->_cur->get_next_sibling();
1023
+ $this->_num++;
1024
+ return $ret;
1025
+ }
1026
+ }
1027
+
1028
+ //------------------------------------------------------------------------
1029
+
1030
+ /**
1031
+ * Pre-order IteratorAggregate
1032
+ *
1033
+ * @access private
1034
+ * @package dompdf
1035
+ */
1036
+ class FrameTreeList implements IteratorAggregate {
1037
+ /**
1038
+ * @var Frame
1039
+ */
1040
+ protected $_root;
1041
+
1042
+ function __construct(Frame $root) { $this->_root = $root; }
1043
+
1044
+ /**
1045
+ * @return FrameTreeIterator
1046
+ */
1047
+ function getIterator() { return new FrameTreeIterator($this->_root); }
1048
+ }
1049
+
1050
+ /**
1051
+ * Pre-order Iterator
1052
+ *
1053
+ * Returns frames in preorder traversal order (parent then children)
1054
+ *
1055
+ * @access private
1056
+ * @package dompdf
1057
+ */
1058
+ class FrameTreeIterator implements Iterator {
1059
+ /**
1060
+ * @var Frame
1061
+ */
1062
+ protected $_root;
1063
+ protected $_stack = array();
1064
+
1065
+ /**
1066
+ * @var int
1067
+ */
1068
+ protected $_num;
1069
+
1070
+ function __construct(Frame $root) {
1071
+ $this->_stack[] = $this->_root = $root;
1072
+ $this->_num = 0;
1073
+ }
1074
+
1075
+ function rewind() {
1076
+ $this->_stack = array($this->_root);
1077
+ $this->_num = 0;
1078
+ }
1079
+
1080
+ /**
1081
+ * @return bool
1082
+ */
1083
+ function valid() { return count($this->_stack) > 0; }
1084
+
1085
+ /**
1086
+ * @return int
1087
+ */
1088
+ function key() { return $this->_num; }
1089
+
1090
+ /**
1091
+ * @var Frame
1092
+ */
1093
+ function current() { return end($this->_stack); }
1094
+
1095
+ /**
1096
+ * @var Frame
1097
+ */
1098
+ function next() {
1099
+ $b = end($this->_stack);
1100
+
1101
+ // Pop last element
1102
+ unset($this->_stack[ key($this->_stack) ]);
1103
+ $this->_num++;
1104
+
1105
+ // Push all children onto the stack in reverse order
1106
+ if ( $c = $b->get_last_child() ) {
1107
+ $this->_stack[] = $c;
1108
+ while ( $c = $c->get_prev_sibling() )
1109
+ $this->_stack[] = $c;
1110
+ }
1111
+ return $b;
1112
+ }
1113
+ }
dompdf/include/frame_decorator.cls.php ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: frame_decorator.cls.php 464 2012-01-30 20:44:53Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Base Frame_Decorator class
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ abstract class Frame_Decorator extends Frame {
17
+ const DEFAULT_COUNTER = "-dompdf-default-counter";
18
+
19
+ public $_counters = array(); // array([id] => counter_value) (for generated content)
20
+
21
+ /**
22
+ * The root node of the DOM tree
23
+ *
24
+ * @var Frame
25
+ */
26
+ protected $_root;
27
+
28
+ /**
29
+ * The decorated frame
30
+ *
31
+ * @var Frame
32
+ */
33
+ protected $_frame;
34
+
35
+ /**
36
+ * Positioner object used to position this frame (Strategy pattern)
37
+ *
38
+ * @var Positioner
39
+ */
40
+ protected $_positioner;
41
+
42
+ /**
43
+ * Reflower object used to calculate frame dimensions (Strategy pattern)
44
+ *
45
+ * @var Frame_Reflower
46
+ */
47
+ protected $_reflower;
48
+
49
+ /**
50
+ * Reference to the current dompdf instance
51
+ *
52
+ * @var DOMPDF
53
+ */
54
+ protected $_dompdf;
55
+
56
+ /**
57
+ * First block parent
58
+ *
59
+ * @var Block_Frame_Decorator
60
+ */
61
+ private $_block_parent;
62
+
63
+ /**
64
+ * First positionned parent (position: relative | absolute | fixed)
65
+ *
66
+ * @var Frame_Decorator
67
+ */
68
+ private $_positionned_parent;
69
+
70
+ /**
71
+ * Class constructor
72
+ *
73
+ * @param Frame $frame the decoration target
74
+ */
75
+ function __construct(Frame $frame, DOMPDF $dompdf) {
76
+ $this->_frame = $frame;
77
+ $this->_root = null;
78
+ $this->_dompdf = $dompdf;
79
+ $frame->set_decorator($this);
80
+ }
81
+
82
+ /**
83
+ * "Destructor": foribly free all references held by this object
84
+ *
85
+ * @param bool $recursive if true, call dispose on all children
86
+ */
87
+ function dispose($recursive = false) {
88
+
89
+ if ( $recursive ) {
90
+ while ( $child = $this->get_first_child() )
91
+ $child->dispose(true);
92
+ }
93
+
94
+ $this->_root = null;
95
+ unset($this->_root);
96
+
97
+ $this->_frame->dispose(true);
98
+ $this->_frame = null;
99
+ unset($this->_frame);
100
+
101
+ $this->_positioner = null;
102
+ unset($this->_positioner);
103
+
104
+ $this->_reflower = null;
105
+ unset($this->_reflower);
106
+ }
107
+
108
+ /**
109
+ * Return a copy of this frame with $node as its node
110
+ *
111
+ * @param DomNode $node
112
+ * @return Frame
113
+ */
114
+ function copy(DomNode $node) {
115
+ $frame = new Frame($node);
116
+ $frame->set_style(clone $this->_frame->get_original_style());
117
+ $deco = Frame_Factory::decorate_frame($frame, $this->_dompdf);
118
+ $deco->set_root($this->_root);
119
+ return $deco;
120
+ }
121
+
122
+ /**
123
+ * Create a deep copy: copy this node and all children
124
+ *
125
+ * @return Frame
126
+ */
127
+ function deep_copy() {
128
+ $frame = new Frame($this->get_node()->cloneNode());
129
+ $frame->set_style(clone $this->_frame->get_original_style());
130
+ $deco = Frame_Factory::decorate_frame($frame, $this->_dompdf);
131
+ $deco->set_root($this->_root);
132
+
133
+ foreach ($this->get_children() as $child)
134
+ $deco->append_child($child->deep_copy());
135
+
136
+ return $deco;
137
+ }
138
+ //........................................................................
139
+
140
+ /**
141
+ * Delegate calls to decorated frame object
142
+ */
143
+ function reset() {
144
+ $this->_frame->reset();
145
+
146
+ $this->_counters = array();
147
+
148
+ // Reset all children
149
+ foreach ($this->get_children() as $child)
150
+ $child->reset();
151
+ }
152
+
153
+ // Getters -----------
154
+ function get_id() { return $this->_frame->get_id(); }
155
+
156
+ /**
157
+ * @return Frame
158
+ */
159
+ function get_frame() { return $this->_frame; }
160
+
161
+ /**
162
+ * @return DomNode
163
+ */
164
+ function get_node() { return $this->_frame->get_node(); }
165
+
166
+ /**
167
+ * @return Style
168
+ */
169
+ function get_style() { return $this->_frame->get_style(); }
170
+
171
+ /**
172
+ * @return Style
173
+ */
174
+ function get_original_style() { return $this->_frame->get_original_style(); }
175
+ function get_containing_block($i = null) { return $this->_frame->get_containing_block($i); }
176
+ function get_position($i = null) { return $this->_frame->get_position($i); }
177
+
178
+ /**
179
+ * @return DOMPDF
180
+ */
181
+ function get_dompdf() { return $this->_dompdf; }
182
+
183
+ function get_margin_height() { return $this->_frame->get_margin_height(); }
184
+ function get_margin_width() { return $this->_frame->get_margin_width(); }
185
+ function get_padding_box() { return $this->_frame->get_padding_box(); }
186
+ function get_border_box() { return $this->_frame->get_border_box(); }
187
+
188
+ // Setters -----------
189
+ function set_id($id) { $this->_frame->set_id($id); }
190
+ function set_style(Style $style) { $this->_frame->set_style($style); }
191
+
192
+ function set_containing_block($x = null, $y = null, $w = null, $h = null) {
193
+ $this->_frame->set_containing_block($x, $y, $w, $h);
194
+ }
195
+
196
+ function set_position($x = null, $y = null) {
197
+ $this->_frame->set_position($x, $y);
198
+ }
199
+ function __toString() { return $this->_frame->__toString(); }
200
+
201
+ function prepend_child(Frame $child, $update_node = true) {
202
+ while ( $child instanceof Frame_Decorator )
203
+ $child = $child->_frame;
204
+
205
+ $this->_frame->prepend_child($child, $update_node);
206
+ }
207
+
208
+ function append_child(Frame $child, $update_node = true) {
209
+ while ( $child instanceof Frame_Decorator )
210
+ $child = $child->_frame;
211
+
212
+ $this->_frame->append_child($child, $update_node);
213
+ }
214
+
215
+ function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) {
216
+ while ( $new_child instanceof Frame_Decorator )
217
+ $new_child = $new_child->_frame;
218
+
219
+ if ( $ref instanceof Frame_Decorator )
220
+ $ref = $ref->_frame;
221
+
222
+ $this->_frame->insert_child_before($new_child, $ref, $update_node);
223
+ }
224
+
225
+ function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) {
226
+ while ( $new_child instanceof Frame_Decorator )
227
+ $new_child = $new_child->_frame;
228
+
229
+ while ( $ref instanceof Frame_Decorator )
230
+ $ref = $ref->_frame;
231
+
232
+ $this->_frame->insert_child_after($new_child, $ref, $update_node);
233
+ }
234
+
235
+ function remove_child(Frame $child, $update_node = true) {
236
+ while ( $child instanceof Frame_Decorator )
237
+ $child = $new_child->_frame;
238
+
239
+ $this->_frame->remove_child($child, $update_node);
240
+ }
241
+
242
+ //........................................................................
243
+
244
+ /**
245
+ * @return Frame_Decorator
246
+ */
247
+ function get_parent() {
248
+ $p = $this->_frame->get_parent();
249
+ if ( $p && $deco = $p->get_decorator() ) {
250
+ while ( $tmp = $deco->get_decorator() )
251
+ $deco = $tmp;
252
+ return $deco;
253
+ } else if ( $p )
254
+ return $p;
255
+ else
256
+ return null;
257
+ }
258
+
259
+ /**
260
+ * @return Frame_Decorator
261
+ */
262
+ function get_first_child() {
263
+ $c = $this->_frame->get_first_child();
264
+ if ( $c && $deco = $c->get_decorator() ) {
265
+ while ( $tmp = $deco->get_decorator() )
266
+ $deco = $tmp;
267
+ return $deco;
268
+ } else if ( $c )
269
+ return $c;
270
+ else
271
+ return null;
272
+ }
273
+
274
+ /**
275
+ * @return Frame_Decorator
276
+ */
277
+ function get_last_child() {
278
+ $c = $this->_frame->get_last_child();
279
+ if ( $c && $deco = $c->get_decorator() ) {
280
+ while ( $tmp = $deco->get_decorator() )
281
+ $deco = $tmp;
282
+ return $deco;
283
+ } else if ( $c )
284
+ return $c;
285
+ else
286
+ return null;
287
+ }
288
+
289
+ /**
290
+ * @return Frame_Decorator
291
+ */
292
+ function get_prev_sibling() {
293
+ $s = $this->_frame->get_prev_sibling();
294
+ if ( $s && $deco = $s->get_decorator() ) {
295
+ while ( $tmp = $deco->get_decorator() )
296
+ $deco = $tmp;
297
+ return $deco;
298
+ } else if ( $s )
299
+ return $s;
300
+ else
301
+ return null;
302
+ }
303
+
304
+ /**
305
+ * @return Frame_Decorator
306
+ */
307
+ function get_next_sibling() {
308
+ $s = $this->_frame->get_next_sibling();
309
+ if ( $s && $deco = $s->get_decorator() ) {
310
+ while ( $tmp = $deco->get_decorator() )
311
+ $deco = $tmp;
312
+ return $deco;
313
+ } else if ( $s )
314
+ return $s;
315
+ else
316
+ return null;
317
+ }
318
+
319
+ /**
320
+ * @return FrameTreeList
321
+ */
322
+ function get_subtree() {
323
+ return new FrameTreeList($this);
324
+ }
325
+
326
+ //........................................................................
327
+
328
+ function set_positioner(Positioner $posn) {
329
+ $this->_positioner = $posn;
330
+ if ( $this->_frame instanceof Frame_Decorator )
331
+ $this->_frame->set_positioner($posn);
332
+ }
333
+
334
+ //........................................................................
335
+
336
+ function set_reflower(Frame_Reflower $reflower) {
337
+ $this->_reflower = $reflower;
338
+ if ( $this->_frame instanceof Frame_Decorator )
339
+ $this->_frame->set_reflower( $reflower );
340
+ }
341
+
342
+ /**
343
+ * @return Frame_Reflower
344
+ */
345
+ function get_reflower() { return $this->_reflower; }
346
+
347
+ //........................................................................
348
+
349
+ function set_root(Frame $root) {
350
+ $this->_root = $root;
351
+ if ( $this->_frame instanceof Frame_Decorator )
352
+ $this->_frame->set_root($root);
353
+ }
354
+
355
+ /**
356
+ * @return Page_Frame_Decorator
357
+ */
358
+ function get_root() { return $this->_root; }
359
+
360
+ //........................................................................
361
+
362
+ /**
363
+ * @return Block_Frame_Decorator
364
+ */
365
+ function find_block_parent() {
366
+ /*if ( $this->_block_parent && !isset($this->_block_parent->_splitted) ) {
367
+ return $this->_block_parent;
368
+ }*/
369
+
370
+ // Find our nearest block level parent
371
+ $p = $this->get_parent();
372
+
373
+ while ( $p ) {
374
+ if ( $p->is_block() ) break;
375
+ $p = $p->get_parent();
376
+ }
377
+
378
+ return $this->_block_parent = $p;
379
+ }
380
+
381
+ /**
382
+ * @return Frame_Decorator
383
+ */
384
+ function find_positionned_parent() {
385
+ /*if ( $this->_positionned_parent && !isset($this->_block_parent->_splitted) ) {
386
+ return $this->_positionned_parent;
387
+ }*/
388
+
389
+ // Find our nearest relative positionned parent
390
+ $p = $this->get_parent();
391
+ while ( $p ) {
392
+ if ( $p->is_positionned() ) break;
393
+ $p = $p->get_parent();
394
+ }
395
+
396
+ if ( !$p ) {
397
+ $p = $this->_root->get_first_child(); // <body>
398
+ }
399
+
400
+ return $this->_positionned_parent = $p;
401
+ }
402
+
403
+ //........................................................................
404
+
405
+ /**
406
+ * split this frame at $child.
407
+ *
408
+ * The current frame is cloned and $child and all children following
409
+ * $child are added to the clone. The clone is then passed to the
410
+ * current frame's parent->split() method.
411
+ *
412
+ * @param Frame $child
413
+ * @param boolean $force_pagebreak
414
+ */
415
+ function split($child = null, $force_pagebreak = false) {
416
+ if ( is_null( $child ) ) {
417
+ $this->get_parent()->split($this, $force_pagebreak);
418
+ return;
419
+ }
420
+
421
+ if ( $child->get_parent() !== $this )
422
+ throw new DOMPDF_Exception("Unable to split: frame is not a child of this one.");
423
+
424
+ $node = $this->_frame->get_node();
425
+
426
+ // mark the frame as splitted (don't use the find_***_parent cache)
427
+ //$this->_splitted = true;
428
+
429
+ $split = $this->copy( $node->cloneNode() );
430
+ $split->reset();
431
+ $split->get_original_style()->text_indent = 0;
432
+
433
+ // The body's properties must be kept
434
+ if ( $node->nodeName !== "body" ) {
435
+ // Style reset on the first and second parts
436
+ $style = $this->_frame->get_style();
437
+ $style->margin_bottom = 0;
438
+ $style->padding_bottom = 0;
439
+ $style->border_bottom = 0;
440
+
441
+ // second
442
+ $orig_style = $split->get_original_style();
443
+ $orig_style->text_indent = 0;
444
+ $orig_style->margin_top = 0;
445
+ $orig_style->padding_top = 0;
446
+ $orig_style->border_top = 0;
447
+ }
448
+
449
+ $this->get_parent()->insert_child_after($split, $this);
450
+
451
+ // Add $frame and all following siblings to the new split node
452
+ $iter = $child;
453
+ while ($iter) {
454
+ $frame = $iter;
455
+ $iter = $iter->get_next_sibling();
456
+ $frame->reset();
457
+ $split->append_child($frame);
458
+ }
459
+
460
+ $this->get_parent()->split($split, $force_pagebreak);
461
+ }
462
+
463
+ function reset_counter($id = self::DEFAULT_COUNTER, $value = 0) {
464
+ $this->get_parent()->_counters[$id] = $value;
465
+ }
466
+
467
+ function increment_counters($counters) {
468
+ foreach($counters as $id => $increment) {
469
+ $this->increment_counter($id, $increment);
470
+ }
471
+ }
472
+
473
+ function increment_counter($id = self::DEFAULT_COUNTER, $increment = 1) {
474
+ $counter_frame = $this->lookup_counter_frame($id);
475
+
476
+ if ( $counter_frame ) {
477
+ if ( !isset($counter_frame->_counters[$id]) ) {
478
+ $counter_frame->_counters[$id] = 0;
479
+ }
480
+
481
+ $counter_frame->_counters[$id] += $increment;
482
+ }
483
+ }
484
+
485
+ function lookup_counter_frame($id = self::DEFAULT_COUNTER) {
486
+ $f = $this->get_parent();
487
+
488
+ while( $f ) {
489
+ if( isset($f->_counters[$id]) ) {
490
+ return $f;
491
+ }
492
+ $fp = $f->get_parent();
493
+
494
+ if ( !$fp ) {
495
+ return $f;
496
+ }
497
+
498
+ $f = $fp;
499
+ }
500
+ }
501
+
502
+ // TODO: What version is the best : this one or the one in List_Bullet_Renderer ?
503
+ function counter_value($id = self::DEFAULT_COUNTER, $type = "decimal") {
504
+ $type = mb_strtolower($type);
505
+
506
+ if ( !isset($this->_counters[$id]) ) {
507
+ $value = $this->_counters[$id] = 0;
508
+ }
509
+ else {
510
+ $value = $this->_counters[$id];
511
+ }
512
+
513
+ switch ($type) {
514
+
515
+ default:
516
+ case "decimal":
517
+ return $value;
518
+
519
+ case "decimal-leading-zero":
520
+ return str_pad($value, 2, "0");
521
+
522
+ case "lower-roman":
523
+ return dec2roman($value);
524
+
525
+ case "upper-roman":
526
+ return mb_strtoupper(dec2roman($value));
527
+
528
+ case "lower-latin":
529
+ case "lower-alpha":
530
+ return chr( ($value % 26) + ord('a') - 1);
531
+
532
+ case "upper-latin":
533
+ case "upper-alpha":
534
+ return chr( ($value % 26) + ord('A') - 1);
535
+
536
+ case "lower-greek":
537
+ return unichr($value + 944);
538
+
539
+ case "upper-greek":
540
+ return unichr($value + 912);
541
+ }
542
+ }
543
+
544
+ //........................................................................
545
+
546
+ final function position() { $this->_positioner->position(); }
547
+
548
+ final function move($offset_x, $offset_y, $ignore_self = false) {
549
+ $this->_positioner->move($offset_x, $offset_y, $ignore_self);
550
+ }
551
+
552
+ final function reflow(Frame_Decorator $block = null) {
553
+ // Uncomment this to see the frames before they're laid out, instead of
554
+ // during rendering.
555
+ //echo $this->_frame; flush();
556
+ $this->_reflower->reflow($block);
557
+ }
558
+
559
+ final function get_min_max_width() { return $this->_reflower->get_min_max_width(); }
560
+
561
+ //........................................................................
562
+ }
dompdf/include/frame_factory.cls.php ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: frame_factory.cls.php 470 2012-02-06 19:36:13Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Contains frame decorating logic
12
+ *
13
+ * This class is responsible for assigning the correct {@link Frame_Decorator},
14
+ * {@link Positioner}, and {@link Frame_Reflower} objects to {@link Frame}
15
+ * objects. This is determined primarily by the Frame's display type, but
16
+ * also by the Frame's node's type (e.g. DomElement vs. #text)
17
+ *
18
+ * @access private
19
+ * @package dompdf
20
+ */
21
+ class Frame_Factory {
22
+
23
+ /**
24
+ * Decorate the root Frame
25
+ *
26
+ * @param $root Frame The frame to decorate
27
+ * @param $dompdf DOMPDF The dompdf instance
28
+ * @return Page_Frame_Decorator
29
+ */
30
+ static function decorate_root(Frame $root, DOMPDF $dompdf) {
31
+ $frame = new Page_Frame_Decorator($root, $dompdf);
32
+ $frame->set_reflower( new Page_Frame_Reflower($frame) );
33
+ $root->set_decorator($frame);
34
+ return $frame;
35
+ }
36
+
37
+ /**
38
+ * Decorate a Frame
39
+ *
40
+ * @param $root Frame The frame to decorate
41
+ * @param $dompdf DOMPDF The dompdf instance
42
+ * @return Frame_Decorator
43
+ * FIXME: this is admittedly a little smelly...
44
+ */
45
+ static function decorate_frame(Frame $frame, DOMPDF $dompdf) {
46
+ if ( is_null($dompdf) )
47
+ throw new Exception("foo");
48
+
49
+ $style = $frame->get_style();
50
+
51
+ switch ($style->display) {
52
+
53
+ case "block":
54
+ $positioner = "Block";
55
+ $decorator = "Block";
56
+ $reflower = "Block";
57
+ break;
58
+
59
+ case "inline-block":
60
+ $positioner = "Inline";
61
+ $decorator = "Block";
62
+ $reflower = "Block";
63
+ break;
64
+
65
+ case "inline":
66
+ $positioner = "Inline";
67
+ if ( $frame->is_text_node() ) {
68
+ $decorator = "Text";
69
+ $reflower = "Text";
70
+ }
71
+ else {
72
+ if ( DOMPDF_ENABLE_CSS_FLOAT && $style->float !== "none" ) {
73
+ $decorator = "Block";
74
+ $reflower = "Block";
75
+ }
76
+ else {
77
+ $decorator = "Inline";
78
+ $reflower = "Inline";
79
+ }
80
+ }
81
+ break;
82
+
83
+ case "table":
84
+ $positioner = "Block";
85
+ $decorator = "Table";
86
+ $reflower = "Table";
87
+ break;
88
+
89
+ case "inline-table":
90
+ $positioner = "Inline";
91
+ $decorator = "Table";
92
+ $reflower = "Table";
93
+ break;
94
+
95
+ case "table-row-group":
96
+ case "table-header-group":
97
+ case "table-footer-group":
98
+ $positioner = "Null";
99
+ $decorator = "Table_Row_Group";
100
+ $reflower = "Table_Row_Group";
101
+ break;
102
+
103
+ case "table-row":
104
+ $positioner = "Null";
105
+ $decorator = "Table_Row";
106
+ $reflower = "Table_Row";
107
+ break;
108
+
109
+ case "table-cell":
110
+ $positioner = "Table_Cell";
111
+ $decorator = "Table_Cell";
112
+ $reflower = "Table_Cell";
113
+ break;
114
+
115
+ case "list-item":
116
+ $positioner = "Block";
117
+ $decorator = "Block";
118
+ $reflower = "Block";
119
+ break;
120
+
121
+ case "-dompdf-list-bullet":
122
+ if ( $style->list_style_position === "inside" )
123
+ $positioner = "Inline";
124
+ else
125
+ $positioner = "List_Bullet";
126
+
127
+ if ( $style->list_style_image !== "none" )
128
+ $decorator = "List_Bullet_Image";
129
+ else
130
+ $decorator = "List_Bullet";
131
+
132
+ $reflower = "List_Bullet";
133
+ break;
134
+
135
+ case "-dompdf-image":
136
+ $positioner = "Inline";
137
+ $decorator = "Image";
138
+ $reflower = "Image";
139
+ break;
140
+
141
+ case "-dompdf-br":
142
+ $positioner = "Inline";
143
+ $decorator = "Inline";
144
+ $reflower = "Inline";
145
+ break;
146
+
147
+ default:
148
+ // FIXME: should throw some sort of warning or something?
149
+ case "none":
150
+ $positioner = "Null";
151
+ $decorator = "Null";
152
+ $reflower = "Null";
153
+ break;
154
+ }
155
+
156
+ // Handle CSS position
157
+ $position = $style->position;
158
+
159
+ if ( $position === "absolute" )
160
+ $positioner = "Absolute";
161
+
162
+ else if ( $position === "fixed" )
163
+ $positioner = "Fixed";
164
+
165
+ // Handle nodeName
166
+ $node_name = $frame->get_node()->nodeName;
167
+
168
+ if ( $node_name === "img" ) {
169
+ $style->display = "-dompdf-image";
170
+ $decorator = "Image";
171
+ $reflower = "Image";
172
+ }
173
+
174
+ $positioner .= "_Positioner";
175
+ $decorator .= "_Frame_Decorator";
176
+ $reflower .= "_Frame_Reflower";
177
+
178
+ $deco = new $decorator($frame, $dompdf);
179
+ $deco->set_positioner( new $positioner($deco) );
180
+ $reflow = new $reflower($deco);
181
+
182
+ $deco->set_reflower( $reflow );
183
+
184
+ return $deco;
185
+ }
186
+ }
dompdf/include/frame_reflower.cls.php ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Base reflower class
12
+ *
13
+ * Reflower objects are responsible for determining the width and height of
14
+ * individual frames. They also create line and page breaks as necessary.
15
+ *
16
+ * @access private
17
+ * @package dompdf
18
+ */
19
+ abstract class Frame_Reflower {
20
+
21
+ /**
22
+ * Frame for this reflower
23
+ *
24
+ * @var Frame
25
+ */
26
+ protected $_frame;
27
+
28
+ /**
29
+ * Cached min/max size
30
+ *
31
+ * @var array
32
+ */
33
+ protected $_min_max_cache;
34
+
35
+ function __construct(Frame $frame) {
36
+ $this->_frame = $frame;
37
+ $this->_min_max_cache = null;
38
+ }
39
+
40
+ function dispose() {
41
+ clear_object($this);
42
+ }
43
+
44
+ /**
45
+ * Collapse frames margins
46
+ * http://www.w3.org/TR/CSS2/box.html#collapsing-margins
47
+ */
48
+ protected function _collapse_margins() {
49
+ $frame = $this->_frame;
50
+ $cb = $frame->get_containing_block();
51
+ $style = $frame->get_style();
52
+
53
+ if ( !$frame->is_in_flow() ) {
54
+ return;
55
+ }
56
+
57
+ $t = $style->length_in_pt($style->margin_top, $cb["h"]);
58
+ $b = $style->length_in_pt($style->margin_bottom, $cb["h"]);
59
+
60
+ // Handle 'auto' values
61
+ if ( $t === "auto" ) {
62
+ $style->margin_top = "0pt";
63
+ $t = 0;
64
+ }
65
+
66
+ if ( $b === "auto" ) {
67
+ $style->margin_bottom = "0pt";
68
+ $b = 0;
69
+ }
70
+
71
+ // Collapse vertical margins:
72
+ $n = $frame->get_next_sibling();
73
+ if ( $n && !$n->is_block() ) {
74
+ while ( $n = $n->get_next_sibling() ) {
75
+ if ( $n->is_block() ) {
76
+ break;
77
+ }
78
+
79
+ if ( !$n->get_first_child() ) {
80
+ $n = null;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+
86
+ if ( $n ) {
87
+ $n_style = $n->get_style();
88
+ $b = max($b, $n_style->length_in_pt($n_style->margin_top, $cb["h"]));
89
+ $n_style->margin_top = "0pt";
90
+ $style->margin_bottom = $b."pt";
91
+ }
92
+
93
+ // Collapse our first child's margin
94
+ /*$f = $this->_frame->get_first_child();
95
+ if ( $f && !$f->is_block() ) {
96
+ while ( $f = $f->get_next_sibling() ) {
97
+ if ( $f->is_block() ) {
98
+ break;
99
+ }
100
+
101
+ if ( !$f->get_first_child() ) {
102
+ $f = null;
103
+ break;
104
+ }
105
+ }
106
+ }
107
+
108
+ // Margin are collapsed only between block elements
109
+ if ( $f ) {
110
+ $f_style = $f->get_style();
111
+ $t = max($t, $f_style->length_in_pt($f_style->margin_top, $cb["h"]));
112
+ $style->margin_top = $t."pt";
113
+ $f_style->margin_bottom = "0pt";
114
+ }*/
115
+ }
116
+
117
+ //........................................................................
118
+
119
+ abstract function reflow(Frame_Decorator $block = null);
120
+
121
+ //........................................................................
122
+
123
+ // Required for table layout: Returns an array(0 => min, 1 => max, "min"
124
+ // => min, "max" => max) of the minimum and maximum widths of this frame.
125
+ // This provides a basic implementation. Child classes should override
126
+ // this if necessary.
127
+ function get_min_max_width() {
128
+ if ( !is_null($this->_min_max_cache) ) {
129
+ return $this->_min_max_cache;
130
+ }
131
+
132
+ $style = $this->_frame->get_style();
133
+
134
+ // Account for margins & padding
135
+ $dims = array($style->padding_left,
136
+ $style->padding_right,
137
+ $style->border_left_width,
138
+ $style->border_right_width,
139
+ $style->margin_left,
140
+ $style->margin_right);
141
+
142
+ $cb_w = $this->_frame->get_containing_block("w");
143
+ $delta = $style->length_in_pt($dims, $cb_w);
144
+
145
+ // Handle degenerate case
146
+ if ( !$this->_frame->get_first_child() )
147
+ return $this->_min_max_cache = array($delta, $delta,"min" => $delta, "max" => $delta);
148
+
149
+ $low = array();
150
+ $high = array();
151
+
152
+ for ( $iter = $this->_frame->get_children()->getIterator();
153
+ $iter->valid();
154
+ $iter->next() ) {
155
+
156
+ $inline_min = 0;
157
+ $inline_max = 0;
158
+
159
+ // Add all adjacent inline widths together to calculate max width
160
+ while ( $iter->valid() && in_array( $iter->current()->get_style()->display, Style::$INLINE_TYPES ) ) {
161
+
162
+ $child = $iter->current();
163
+
164
+ $minmax = $child->get_min_max_width();
165
+
166
+ if ( in_array( $iter->current()->get_style()->white_space, array("pre", "nowrap") ) )
167
+ $inline_min += $minmax["min"];
168
+ else
169
+ $low[] = $minmax["min"];
170
+
171
+ $inline_max += $minmax["max"];
172
+ $iter->next();
173
+
174
+ }
175
+
176
+ if ( $inline_max > 0 )
177
+ $high[] = $inline_max;
178
+
179
+ if ( $inline_min > 0 )
180
+ $low[] = $inline_min;
181
+
182
+ if ( $iter->valid() ) {
183
+ list($low[], $high[]) = $iter->current()->get_min_max_width();
184
+ continue;
185
+ }
186
+
187
+ }
188
+ $min = count($low) ? max($low) : 0;
189
+ $max = count($high) ? max($high) : 0;
190
+
191
+ // Use specified width if it is greater than the minimum defined by the
192
+ // content. If the width is a percentage ignore it for now.
193
+ $width = $style->width;
194
+ if ( $width !== "auto" && !is_percent($width) ) {
195
+ $width = $style->length_in_pt($width, $cb_w);
196
+ if ( $min < $width )
197
+ $min = $width;
198
+ if ( $max < $width )
199
+ $max = $width;
200
+ }
201
+
202
+ $min += $delta;
203
+ $max += $delta;
204
+ return $this->_min_max_cache = array($min, $max, "min"=>$min, "max"=>$max);
205
+ }
206
+
207
+ /**
208
+ * Parses a CSS string containing quotes and escaped hex characters
209
+ *
210
+ * @param $string string The CSS string to parse
211
+ * @param $single_trim
212
+ * @return string
213
+ */
214
+ protected function _parse_string($string, $single_trim = false) {
215
+ if ($single_trim) {
216
+ $string = preg_replace("/^[\"\']/", "", $string);
217
+ $string = preg_replace("/[\"\']$/", "", $string);
218
+ }
219
+ else {
220
+ $string = trim($string, "'\"");
221
+ }
222
+
223
+ $string = str_replace(array("\\\n",'\\"',"\\'"),
224
+ array("",'"',"'"), $string);
225
+
226
+ // Convert escaped hex characters into ascii characters (e.g. \A => newline)
227
+ $string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})(\s)?(?(2)|(?=[^0-9a-fA-F]))/",
228
+ create_function('$matches',
229
+ 'return chr(hexdec($matches[1]));'),
230
+ $string);
231
+ return $string;
232
+ }
233
+
234
+ /**
235
+ * Parses a CSS "quotes" property
236
+ *
237
+ * @return array An array of pairs of quotes
238
+ */
239
+ protected function _parse_quotes() {
240
+
241
+ // Matches quote types
242
+ $re = "/(\'[^\']*\')|(\"[^\"]*\")/";
243
+
244
+ $quotes = $this->_frame->get_style()->quotes;
245
+
246
+ // split on spaces, except within quotes
247
+ if (!preg_match_all($re, "$quotes", $matches, PREG_SET_ORDER))
248
+ return;
249
+
250
+ $quotes_array = array();
251
+ foreach($matches as &$_quote){
252
+ $quotes_array[] = $this->_parse_string($_quote[0], true);
253
+ }
254
+
255
+ if ( empty($quotes_array) ) {
256
+ $quotes_array = array('"', '"');
257
+ }
258
+
259
+ return array_chunk($quotes_array, 2);
260
+ }
261
+
262
+ /**
263
+ * Parses the CSS "content" property
264
+ *
265
+ * @return string The resulting string
266
+ */
267
+ protected function _parse_content() {
268
+
269
+ // Matches generated content
270
+ $re = "/\n".
271
+ "\s(counters?\\([^)]*\\))|\n".
272
+ "\A(counters?\\([^)]*\\))|\n".
273
+ "\s([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?<!\\\\)\\3|\n".
274
+ "\A([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?<!\\\\)\\5|\n" .
275
+ "\s([^\s\"']+)|\n" .
276
+ "\A([^\s\"']+)\n".
277
+ "/xi";
278
+
279
+ $content = $this->_frame->get_style()->content;
280
+
281
+ $quotes = $this->_parse_quotes();
282
+
283
+ // split on spaces, except within quotes
284
+ if (!preg_match_all($re, $content, $matches, PREG_SET_ORDER))
285
+ return;
286
+
287
+ $text = "";
288
+
289
+ foreach ($matches as $match) {
290
+
291
+ if ( isset($match[2]) && $match[2] !== "" )
292
+ $match[1] = $match[2];
293
+
294
+ if ( isset($match[6]) && $match[6] !== "" )
295
+ $match[4] = $match[6];
296
+
297
+ if ( isset($match[8]) && $match[8] !== "" )
298
+ $match[7] = $match[8];
299
+
300
+ if ( isset($match[1]) && $match[1] !== "" ) {
301
+
302
+ // counters?(...)
303
+ $match[1] = mb_strtolower(trim($match[1]));
304
+
305
+ // Handle counter() references:
306
+ // http://www.w3.org/TR/CSS21/generate.html#content
307
+
308
+ $i = mb_strpos($match[1], ")");
309
+ if ( $i === false )
310
+ continue;
311
+
312
+ $args = explode(",", mb_substr($match[1], 8, $i - 8));
313
+ $counter_id = $args[0];
314
+
315
+ if ( $match[1][7] === "(" ) {
316
+ // counter(name [,style])
317
+
318
+ if ( isset($args[1]) )
319
+ $type = trim($args[1]);
320
+ else
321
+ $type = null;
322
+
323
+ $p = $this->_frame->lookup_counter_frame($counter_id);
324
+
325
+ $text .= $p->counter_value($counter_id, $type);
326
+
327
+ } else if ( $match[1][7] === "s" ) {
328
+ // counters(name, string [,style])
329
+ if ( isset($args[1]) )
330
+ $string = $this->_parse_string(trim($args[1]));
331
+ else
332
+ $string = "";
333
+
334
+ if ( isset($args[2]) )
335
+ $type = $args[2];
336
+ else
337
+ $type = null;
338
+
339
+ $p = $this->_frame->lookup_counter_frame($counter_id);
340
+ $tmp = "";
341
+ while ($p) {
342
+ $tmp = $p->counter_value($counter_id, $type) . $string . $tmp;
343
+ $p = $p->lookup_counter_frame($counter_id);
344
+ }
345
+ $text .= $tmp;
346
+
347
+ } else
348
+ // countertops?
349
+ continue;
350
+
351
+ } else if ( isset($match[4]) && $match[4] !== "" ) {
352
+ // String match
353
+ $text .= $this->_parse_string($match[4]);
354
+
355
+ } else if ( isset($match[7]) && $match[7] !== "" ) {
356
+ // Directive match
357
+
358
+ if ( $match[7] === "open-quote" ) {
359
+ // FIXME: do something here
360
+ $text .= $quotes[0][0];
361
+ } else if ( $match[7] === "close-quote" ) {
362
+ // FIXME: do something else here
363
+ $text .= $quotes[0][1];
364
+ } else if ( $match[7] === "no-open-quote" ) {
365
+ // FIXME:
366
+ } else if ( $match[7] === "no-close-quote" ) {
367
+ // FIXME:
368
+ } else if ( mb_strpos($match[7],"attr(") === 0 ) {
369
+
370
+ $i = mb_strpos($match[7],")");
371
+ if ( $i === false )
372
+ continue;
373
+
374
+ $attr = mb_substr($match[7], 5, $i - 5);
375
+ if ( $attr == "" )
376
+ continue;
377
+
378
+ $text .= $this->_frame->get_parent()->get_node()->getAttribute($attr);
379
+ } else
380
+ continue;
381
+ }
382
+ }
383
+
384
+ return $text;
385
+ }
386
+
387
+ /**
388
+ * Sets the generated content of a generated frame
389
+ */
390
+ protected function _set_content(){
391
+ $frame = $this->_frame;
392
+ $style = $frame->get_style();
393
+
394
+ if ( $style->content && !$frame->get_first_child() && $frame->get_node()->nodeName === "dompdf_generated" ) {
395
+ $content = $this->_parse_content();
396
+ $node = $frame->get_node()->ownerDocument->createTextNode($content);
397
+
398
+ $new_style = $style->get_stylesheet()->create_style();
399
+ $new_style->inherit($style);
400
+
401
+ $new_frame = new Frame($node);
402
+ $new_frame->set_style($new_style);
403
+
404
+ Frame_Factory::decorate_frame($new_frame, $frame->get_dompdf());
405
+ $new_frame->get_decorator()->set_root($frame->get_root());
406
+ $frame->append_child($new_frame);
407
+ }
408
+
409
+ if ( $style->counter_reset && ($reset = $style->counter_reset) !== "none" )
410
+ $frame->reset_counter($reset);
411
+
412
+ if ( $style->counter_increment && ($increment = $style->counter_increment) !== "none" )
413
+ $frame->increment_counters($increment);
414
+ }
415
+ }
dompdf/include/frame_tree.cls.php ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: frame_tree.cls.php 464 2012-01-30 20:44:53Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Represents an entire document as a tree of frames
12
+ *
13
+ * The Frame_Tree consists of {@link Frame} objects each tied to specific
14
+ * DomNode objects in a specific DomDocument. The Frame_Tree has the same
15
+ * structure as the DomDocument, but adds additional capabalities for
16
+ * styling and layout.
17
+ *
18
+ * @package dompdf
19
+ * @access protected
20
+ */
21
+ class Frame_Tree {
22
+
23
+ /**
24
+ * Tags to ignore while parsing the tree
25
+ *
26
+ * @var array
27
+ */
28
+ static protected $_HIDDEN_TAGS = array("area", "base", "basefont", "head", "style",
29
+ "meta", "title", "colgroup",
30
+ "noembed", "noscript", "param", "#comment");
31
+ /**
32
+ * The main DomDocument
33
+ *
34
+ * @see http://ca2.php.net/manual/en/ref.dom.php
35
+ * @var DomDocument
36
+ */
37
+ protected $_dom;
38
+
39
+ /**
40
+ * The root node of the FrameTree.
41
+ *
42
+ * @var Frame
43
+ */
44
+ protected $_root;
45
+
46
+ /**
47
+ * Subtrees of absolutely positioned elements
48
+ *
49
+ * @var array of Frames
50
+ */
51
+ protected $_absolute_frames;
52
+
53
+ /**
54
+ * A mapping of {@link Frame} objects to DomNode objects
55
+ *
56
+ * @var array
57
+ */
58
+ protected $_registry;
59
+
60
+
61
+ /**
62
+ * Class constructor
63
+ *
64
+ * @param DomDocument $dom the main DomDocument object representing the current html document
65
+ */
66
+ function __construct(DomDocument $dom) {
67
+ $this->_dom = $dom;
68
+ $this->_root = null;
69
+ $this->_registry = array();
70
+ }
71
+
72
+ function __destruct() {
73
+ clear_object($this);
74
+ }
75
+
76
+ /**
77
+ * Returns the DomDocument object representing the curent html document
78
+ *
79
+ * @return DomDocument
80
+ */
81
+ function get_dom() { return $this->_dom; }
82
+
83
+ /**
84
+ * Returns the root frame of the tree
85
+ *
86
+ * @return Page_Frame_Decorator
87
+ */
88
+ function get_root() { return $this->_root; }
89
+
90
+ /**
91
+ * Returns a specific frame given its id
92
+ *
93
+ * @param string $id
94
+ * @return Frame
95
+ */
96
+ function get_frame($id) { return isset($this->_registry[$id]) ? $this->_registry[$id] : null; }
97
+
98
+ /**
99
+ * Returns a post-order iterator for all frames in the tree
100
+ *
101
+ * @return FrameTreeList
102
+ */
103
+ function get_frames() { return new FrameTreeList($this->_root); }
104
+
105
+ /**
106
+ * Builds the tree
107
+ */
108
+ function build_tree() {
109
+ $html = $this->_dom->getElementsByTagName("html")->item(0);
110
+ if ( is_null($html) )
111
+ $html = $this->_dom->firstChild;
112
+
113
+ if ( is_null($html) )
114
+ throw new DOMPDF_Exception("Requested HTML document contains no data.");
115
+
116
+ $this->fix_tables();
117
+
118
+ $this->_root = $this->_build_tree_r($html);
119
+
120
+ }
121
+
122
+ /**
123
+ * Adds missing TBODYs around TR
124
+ */
125
+ protected function fix_tables(){
126
+ $xp = new DOMXPath($this->_dom);
127
+
128
+ // Move table caption before the table
129
+ // FIXME find a better way to deal with it...
130
+ $captions = $xp->query("//table/caption");
131
+ foreach($captions as $caption) {
132
+ $table = $caption->parentNode;
133
+ $table->parentNode->insertBefore($caption, $table);
134
+ }
135
+
136
+ $rows = $xp->query("//table/tr");
137
+ foreach($rows as $row) {
138
+ $tbody = $this->_dom->createElement("tbody");
139
+ $tbody = $row->parentNode->insertBefore($tbody, $row);
140
+ $tbody->appendChild($row);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Recursively adds {@link Frame} objects to the tree
146
+ *
147
+ * Recursively build a tree of Frame objects based on a dom tree.
148
+ * No layout information is calculated at this time, although the
149
+ * tree may be adjusted (i.e. nodes and frames for generated content
150
+ * and images may be created).
151
+ *
152
+ * @param DomNode $node the current DomNode being considered
153
+ * @return Frame
154
+ */
155
+ protected function _build_tree_r(DomNode $node) {
156
+
157
+ $frame = new Frame($node);
158
+ $id = $frame->get_id();
159
+ $this->_registry[ $id ] = $frame;
160
+
161
+ if ( !$node->hasChildNodes() )
162
+ return $frame;
163
+
164
+ // Fixes 'cannot access undefined property for object with
165
+ // overloaded access', fix by Stefan radulian
166
+ // <stefan.radulian@symbion.at>
167
+ //foreach ($node->childNodes as $child) {
168
+
169
+ // Store the children in an array so that the tree can be modified
170
+ $children = array();
171
+ for ($i = 0; $i < $node->childNodes->length; $i++)
172
+ $children[] = $node->childNodes->item($i);
173
+
174
+ foreach ($children as $child) {
175
+ $node_name = mb_strtolower($child->nodeName);
176
+
177
+ // Skip non-displaying nodes
178
+ if ( in_array($node_name, self::$_HIDDEN_TAGS) ) {
179
+ if ( $node_name !== "head" &&
180
+ $node_name !== "style" )
181
+ $child->parentNode->removeChild($child);
182
+ continue;
183
+ }
184
+
185
+ // Skip empty text nodes
186
+ if ( $node_name === "#text" && $child->nodeValue == "" ) {
187
+ $child->parentNode->removeChild($child);
188
+ continue;
189
+ }
190
+
191
+ // Skip empty image nodes
192
+ if ( $node_name === "img" && $child->getAttribute("src") == "" ) {
193
+ $child->parentNode->removeChild($child);
194
+ continue;
195
+ }
196
+
197
+ $frame->append_child($this->_build_tree_r($child), false);
198
+ }
199
+
200
+ return $frame;
201
+ }
202
+
203
+ public function insert_node(DOMNode $node, DOMNode $new_node, $pos) {
204
+ if ($pos === "after" || !$node->firstChild)
205
+ $node->appendChild($new_node);
206
+ else
207
+ $node->insertBefore($new_node, $node->firstChild);
208
+
209
+ $this->_build_tree_r($new_node);
210
+
211
+ $frame_id = $new_node->getAttribute("frame_id");
212
+ $frame = $this->get_frame($frame_id);
213
+
214
+ $parent_id = $node->getAttribute("frame_id");
215
+ $parent = $this->get_frame($parent_id);
216
+
217
+ if ($pos === "before")
218
+ $parent->prepend_child($frame, false);
219
+ else
220
+ $parent->append_child($frame, false);
221
+
222
+ return $frame_id;
223
+ }
224
+ }
dompdf/include/functions.inc.php ADDED
@@ -0,0 +1,947 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: functions.inc.php 448 2011-11-13 13:00:03Z fabien.menager $
10
+ */
11
+
12
+ if ( !defined('PHP_VERSION_ID') ) {
13
+ $version = explode('.', PHP_VERSION);
14
+ define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
15
+ }
16
+
17
+ function def($name, $value = true) {
18
+ if (!defined($name)) {
19
+ define($name, $value);
20
+ }
21
+ }
22
+
23
+ if ( !function_exists("pre_r") ) {
24
+ /**
25
+ * print_r wrapper for html/cli output
26
+ *
27
+ * Wraps print_r() output in < pre > tags if the current sapi is not
28
+ * 'cli'. Returns the output string instead of displaying it if $return is
29
+ * true.
30
+ *
31
+ * @param mixed $mixed variable or expression to display
32
+ * @param bool $return
33
+ *
34
+ */
35
+ function pre_r($mixed, $return = false) {
36
+ if ($return)
37
+ return "<pre>" . print_r($mixed, true) . "</pre>";
38
+
39
+ if ( php_sapi_name() !== "cli")
40
+ echo ("<pre>");
41
+ print_r($mixed);
42
+
43
+ if ( php_sapi_name() !== "cli")
44
+ echo("</pre>");
45
+ else
46
+ echo ("\n");
47
+ flush();
48
+
49
+ }
50
+ }
51
+
52
+ if ( !function_exists("pre_var_dump") ) {
53
+ /**
54
+ * var_dump wrapper for html/cli output
55
+ *
56
+ * Wraps var_dump() output in < pre > tags if the current sapi is not
57
+ * 'cli'.
58
+ *
59
+ * @param mixed $mixed variable or expression to display.
60
+ */
61
+ function pre_var_dump($mixed) {
62
+ if ( php_sapi_name() !== "cli")
63
+ echo("<pre>");
64
+
65
+ var_dump($mixed);
66
+
67
+ if ( php_sapi_name() !== "cli")
68
+ echo("</pre>");
69
+ }
70
+ }
71
+
72
+ if ( !function_exists("d") ) {
73
+ /**
74
+ * generic debug function
75
+ *
76
+ * Takes everything and does its best to give a good debug output
77
+ *
78
+ * @param mixed $mixed variable or expression to display.
79
+ */
80
+ function d($mixed) {
81
+ if ( php_sapi_name() !== "cli")
82
+ echo("<pre>");
83
+
84
+ // line
85
+ if ($mixed instanceof Line_Box) {
86
+ echo $mixed;
87
+ }
88
+
89
+ // other
90
+ else {
91
+ var_export($mixed);
92
+ }
93
+
94
+ if ( php_sapi_name() !== "cli")
95
+ echo("</pre>");
96
+ }
97
+ }
98
+
99
+ /**
100
+ * builds a full url given a protocol, hostname, base path and url
101
+ *
102
+ * @param string $protocol
103
+ * @param string $host
104
+ * @param string $base_path
105
+ * @param string $url
106
+ * @return string
107
+ *
108
+ * Initially the trailing slash of $base_path was optional, and conditionally appended.
109
+ * However on dynamically created sites, where the page is given as url parameter,
110
+ * the base path might not end with an url.
111
+ * Therefore do not append a slash, and **require** the $base_url to ending in a slash
112
+ * when needed.
113
+ * Vice versa, on using the local file system path of a file, make sure that the slash
114
+ * is appended (o.k. also for Windows)
115
+ */
116
+ function build_url($protocol, $host, $base_path, $url) {
117
+ if ( strlen($url) == 0 ) {
118
+ //return $protocol . $host . rtrim($base_path, "/\\") . "/";
119
+ return $protocol . $host . $base_path;
120
+ }
121
+
122
+ // Is the url already fully qualified or a Data URI?
123
+ if ( mb_strpos($url, "://") !== false || mb_strpos($url, "data:") === 0 )
124
+ return $url;
125
+
126
+ $ret = $protocol;
127
+
128
+ if (!in_array(mb_strtolower($protocol), array("http://", "https://", "ftp://", "ftps://"))) {
129
+ //On Windows local file, an abs path can begin also with a '\' or a drive letter and colon
130
+ //drive: followed by a relative path would be a drive specific default folder.
131
+ //not known in php app code, treat as abs path
132
+ //($url[1] !== ':' || ($url[2]!=='\\' && $url[2]!=='/'))
133
+ if ($url[0] !== '/' && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' || ($url[0] !== '\\' && $url[1] !== ':'))) {
134
+ // For rel path and local acess we ignore the host, and run the path through realpath()
135
+ $ret .= realpath($base_path).'/';
136
+ }
137
+ $ret .= $url;
138
+ $ret = preg_replace("/\?(.*)$/", "", $ret);
139
+ return $ret;
140
+ }
141
+
142
+ //remote urls with backslash in html/css are not really correct, but lets be genereous
143
+ if ( $url[0] === '/' || $url[0] === '\\' ) {
144
+ // Absolute path
145
+ $ret .= $host . $url;
146
+ } else {
147
+ // Relative path
148
+ //$base_path = $base_path !== "" ? rtrim($base_path, "/\\") . "/" : "";
149
+ $ret .= $host . $base_path . $url;
150
+ }
151
+
152
+ return $ret;
153
+
154
+ }
155
+
156
+ /**
157
+ * parse a full url or pathname and return an array(protocol, host, path,
158
+ * file + query + fragment)
159
+ *
160
+ * @param string $url
161
+ * @return array
162
+ */
163
+ function explode_url($url) {
164
+ $protocol = "";
165
+ $host = "";
166
+ $path = "";
167
+ $file = "";
168
+
169
+ $arr = parse_url($url);
170
+
171
+ if ( isset($arr["scheme"]) &&
172
+ $arr["scheme"] !== "file" &&
173
+ strlen($arr["scheme"]) > 1 ) // Exclude windows drive letters...
174
+ {
175
+ $protocol = $arr["scheme"] . "://";
176
+
177
+ if ( isset($arr["user"]) ) {
178
+ $host .= $arr["user"];
179
+
180
+ if ( isset($arr["pass"]) )
181
+ $host .= "@" . $arr["pass"];
182
+
183
+ $host .= ":";
184
+ }
185
+
186
+ if ( isset($arr["host"]) )
187
+ $host .= $arr["host"];
188
+
189
+ if ( isset($arr["port"]) )
190
+ $host .= ":" . $arr["port"];
191
+
192
+ if ( isset($arr["path"]) && $arr["path"] !== "" ) {
193
+ // Do we have a trailing slash?
194
+ if ( $arr["path"][ mb_strlen($arr["path"]) - 1 ] === "/" ) {
195
+ $path = $arr["path"];
196
+ $file = "";
197
+ } else {
198
+ $path = rtrim(dirname($arr["path"]), '/\\') . "/";
199
+ $file = basename($arr["path"]);
200
+ }
201
+ }
202
+
203
+ if ( isset($arr["query"]) )
204
+ $file .= "?" . $arr["query"];
205
+
206
+ if ( isset($arr["fragment"]) )
207
+ $file .= "#" . $arr["fragment"];
208
+
209
+ } else {
210
+
211
+ $i = mb_strpos($url, "file://");
212
+ if ( $i !== false)
213
+ $url = mb_substr($url, $i + 7);
214
+
215
+ $protocol = ""; // "file://"; ? why doesn't this work... It's because of
216
+ // network filenames like //COMPU/SHARENAME
217
+
218
+ $host = ""; // localhost, really
219
+ $file = basename($url);
220
+
221
+ $path = dirname($url);
222
+
223
+ // Check that the path exists
224
+ if ( $path !== false ) {
225
+ $path .= '/';
226
+
227
+ } else {
228
+ // generate a url to access the file if no real path found.
229
+ $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
230
+
231
+ $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : php_uname("n");
232
+
233
+ if ( substr($arr["path"], 0, 1) === '/' ) {
234
+ $path = dirname($arr["path"]);
235
+ } else {
236
+ $path = '/' . rtrim(dirname($_SERVER["SCRIPT_NAME"]), '/') . '/' . $arr["path"];
237
+ }
238
+ }
239
+ }
240
+
241
+ $ret = array($protocol, $host, $path, $file,
242
+ "protocol" => $protocol,
243
+ "host" => $host,
244
+ "path" => $path,
245
+ "file" => $file);
246
+ return $ret;
247
+ }
248
+
249
+ /**
250
+ * converts decimal numbers to roman numerals
251
+ *
252
+ * @param int $num
253
+ * @return string
254
+ */
255
+ function dec2roman($num) {
256
+
257
+ static $ones = array("", "i", "ii", "iii", "iv", "v",
258
+ "vi", "vii", "viii", "ix");
259
+ static $tens = array("", "x", "xx", "xxx", "xl", "l",
260
+ "lx", "lxx", "lxxx", "xc");
261
+ static $hund = array("", "c", "cc", "ccc", "cd", "d",
262
+ "dc", "dcc", "dccc", "cm");
263
+ static $thou = array("", "m", "mm", "mmm");
264
+
265
+ if ( !is_numeric($num) )
266
+ throw new DOMPDF_Exception("dec2roman() requires a numeric argument.");
267
+
268
+ if ( $num > 4000 || $num < 0 )
269
+ return "(out of range)";
270
+
271
+ $num = strrev((string)$num);
272
+
273
+ $ret = "";
274
+ switch (mb_strlen($num)) {
275
+ case 4: $ret .= $thou[$num[3]];
276
+ case 3: $ret .= $hund[$num[2]];
277
+ case 2: $ret .= $tens[$num[1]];
278
+ case 1: $ret .= $ones[$num[0]];
279
+ default: break;
280
+ }
281
+ return $ret;
282
+
283
+ }
284
+
285
+ /**
286
+ * Determines whether $value is a percentage or not
287
+ *
288
+ * @param float $value
289
+ * @return bool
290
+ */
291
+ function is_percent($value) { return false !== mb_strpos($value, "%"); }
292
+
293
+ /**
294
+ * Parses a data URI scheme
295
+ * http://en.wikipedia.org/wiki/Data_URI_scheme
296
+ * @param string $data_uri The data URI to parse
297
+ * @return array The result with charset, mime type and decoded data
298
+ */
299
+ function parse_data_uri($data_uri) {
300
+ if (!preg_match('/^data:(?P<mime>[a-z0-9\/+-.]+)(;charset=(?P<charset>[a-z0-9-])+)?(?P<base64>;base64)?\,(?P<data>.*)?/i', $data_uri, $match)) {
301
+ return false;
302
+ }
303
+
304
+ $match['data'] = rawurldecode($match['data']);
305
+ $result = array(
306
+ 'charset' => $match['charset'] ? $match['charset'] : 'US-ASCII',
307
+ 'mime' => $match['mime'] ? $match['mime'] : 'text/plain',
308
+ 'data' => $match['base64'] ? base64_decode($match['data']) : $match['data'],
309
+ );
310
+
311
+ return $result;
312
+ }
313
+
314
+ /**
315
+ * mb_string compatibility
316
+ */
317
+ if ( !function_exists("mb_strlen") ) {
318
+
319
+ define('MB_OVERLOAD_MAIL', 1);
320
+ define('MB_OVERLOAD_STRING', 2);
321
+ define('MB_OVERLOAD_REGEX', 4);
322
+ define('MB_CASE_UPPER', 0);
323
+ define('MB_CASE_LOWER', 1);
324
+ define('MB_CASE_TITLE', 2);
325
+
326
+ function mb_convert_encoding($data, $to_encoding, $from_encoding = 'UTF-8') {
327
+ if (str_replace('-', '', strtolower($to_encoding)) === 'utf8') {
328
+ return utf8_encode($data);
329
+ } else {
330
+ return utf8_decode($data);
331
+ }
332
+ }
333
+
334
+ function mb_detect_encoding($data, $encoding_list = array('iso-8859-1'), $strict = false) {
335
+ return 'iso-8859-1';
336
+ }
337
+
338
+ function mb_detect_order($encoding_list = array('iso-8859-1')) {
339
+ return 'iso-8859-1';
340
+ }
341
+
342
+ function mb_internal_encoding($encoding = null) {
343
+ if (isset($encoding)) {
344
+ return true;
345
+ } else {
346
+ return 'iso-8859-1';
347
+ }
348
+ }
349
+
350
+ function mb_strlen($str, $encoding = 'iso-8859-1') {
351
+ switch (str_replace('-', '', strtolower($encoding))) {
352
+ case "utf8": return strlen(utf8_encode($str));
353
+ case "8bit": return strlen($str);
354
+ default: return strlen(utf8_decode($str));
355
+ }
356
+ }
357
+
358
+ function mb_strpos($haystack, $needle, $offset = 0) {
359
+ return strpos($haystack, $needle, $offset);
360
+ }
361
+
362
+ function mb_strrpos($haystack, $needle, $offset = 0) {
363
+ return strrpos($haystack, $needle, $offset);
364
+ }
365
+
366
+ function mb_strtolower( $str ) {
367
+ return strtolower($str);
368
+ }
369
+
370
+ function mb_strtoupper( $str ) {
371
+ return strtoupper($str);
372
+ }
373
+
374
+ function mb_substr($string, $start, $length = null, $encoding = 'iso-8859-1') {
375
+ if ( is_null($length) )
376
+ return substr($string, $start);
377
+ else
378
+ return substr($string, $start, $length);
379
+ }
380
+
381
+ function mb_substr_count($haystack, $needle, $encoding = 'iso-8859-1') {
382
+ return substr_count($haystack, $needle);
383
+ }
384
+
385
+ function mb_encode_numericentity($str, $convmap, $encoding) {
386
+ return htmlspecialchars($str);
387
+ }
388
+
389
+ function mb_convert_case($str, $mode = MB_CASE_UPPER, $encoding = array()) {
390
+ switch($mode) {
391
+ case MB_CASE_UPPER: return mb_strtoupper($str);
392
+ case MB_CASE_LOWER: return mb_strtolower($str);
393
+ case MB_CASE_TITLE: return ucwords(mb_strtolower($str));
394
+ default: return $str;
395
+ }
396
+ }
397
+
398
+ function mb_list_encodings() {
399
+ return array(
400
+ "ISO-8859-1",
401
+ "UTF-8",
402
+ "8bit",
403
+ );
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Decoder for RLE8 compression in windows bitmaps
409
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
410
+ */
411
+ function rle8_decode ($str, $width){
412
+ $lineWidth = $width + (3 - ($width-1) % 4);
413
+ $out = '';
414
+ $cnt = strlen($str);
415
+
416
+ for ($i = 0; $i <$cnt; $i++) {
417
+ $o = ord($str[$i]);
418
+ switch ($o){
419
+ case 0: # ESCAPE
420
+ $i++;
421
+ switch (ord($str[$i])){
422
+ case 0: # NEW LINE
423
+ $padCnt = $lineWidth - strlen($out)%$lineWidth;
424
+ if ($padCnt<$lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line
425
+ break;
426
+ case 1: # END OF FILE
427
+ $padCnt = $lineWidth - strlen($out)%$lineWidth;
428
+ if ($padCnt<$lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line
429
+ break 3;
430
+ case 2: # DELTA
431
+ $i += 2;
432
+ break;
433
+ default: # ABSOLUTE MODE
434
+ $num = ord($str[$i]);
435
+ for ($j = 0; $j < $num; $j++)
436
+ $out .= $str[++$i];
437
+ if ($num % 2) $i++;
438
+ }
439
+ break;
440
+ default:
441
+ $out .= str_repeat($str[++$i], $o);
442
+ }
443
+ }
444
+ return $out;
445
+ }
446
+
447
+ /**
448
+ * Decoder for RLE4 compression in windows bitmaps
449
+ * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
450
+ */
451
+ function rle4_decode ($str, $width) {
452
+ $w = floor($width/2) + ($width % 2);
453
+ $lineWidth = $w + (3 - ( ($width-1) / 2) % 4);
454
+ $pixels = array();
455
+ $cnt = strlen($str);
456
+
457
+ for ($i = 0; $i < $cnt; $i++) {
458
+ $o = ord($str[$i]);
459
+ switch ($o) {
460
+ case 0: # ESCAPE
461
+ $i++;
462
+ switch (ord($str[$i])){
463
+ case 0: # NEW LINE
464
+ while (count($pixels)%$lineWidth!=0)
465
+ $pixels[]=0;
466
+ break;
467
+ case 1: # END OF FILE
468
+ while (count($pixels)%$lineWidth!=0)
469
+ $pixels[]=0;
470
+ break 3;
471
+ case 2: # DELTA
472
+ $i += 2;
473
+ break;
474
+ default: # ABSOLUTE MODE
475
+ $num = ord($str[$i]);
476
+ for ($j = 0; $j < $num; $j++){
477
+ if ($j%2 == 0){
478
+ $c = ord($str[++$i]);
479
+ $pixels[] = ($c & 240)>>4;
480
+ } else
481
+ $pixels[] = $c & 15;
482
+ }
483
+ if ($num % 2 == 0) $i++;
484
+ }
485
+ break;
486
+ default:
487
+ $c = ord($str[++$i]);
488
+ for ($j = 0; $j < $o; $j++)
489
+ $pixels[] = ($j%2==0 ? ($c & 240)>>4 : $c & 15);
490
+ }
491
+ }
492
+
493
+ $out = '';
494
+ if (count($pixels)%2) $pixels[]=0;
495
+ $cnt = count($pixels)/2;
496
+
497
+ for ($i = 0; $i < $cnt; $i++)
498
+ $out .= chr(16*$pixels[2*$i] + $pixels[2*$i+1]);
499
+
500
+ return $out;
501
+ }
502
+
503
+ if ( !function_exists("imagecreatefrombmp") ) {
504
+
505
+ /**
506
+ * Credit goes to mgutt
507
+ * http://www.programmierer-forum.de/function-imagecreatefrombmp-welche-variante-laeuft-t143137.htm
508
+ * Modified by Fabien Menager to support RGB555 BMP format
509
+ */
510
+ function imagecreatefrombmp($filename) {
511
+ try {
512
+ // version 1.00
513
+ if (!($fh = fopen($filename, 'rb'))) {
514
+ trigger_error('imagecreatefrombmp: Can not open ' . $filename, E_USER_WARNING);
515
+ return false;
516
+ }
517
+
518
+ $bytes_read = 0;
519
+
520
+ // read file header
521
+ $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14));
522
+
523
+ // check for bitmap
524
+ if ($meta['type'] != 19778) {
525
+ trigger_error('imagecreatefrombmp: ' . $filename . ' is not a bitmap!', E_USER_WARNING);
526
+ return false;
527
+ }
528
+
529
+ // read image header
530
+ $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40));
531
+ $bytes_read += 40;
532
+
533
+ // read additional bitfield header
534
+ if ($meta['compression'] == 3) {
535
+ $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12));
536
+ $bytes_read += 12;
537
+ }
538
+
539
+ // set bytes and padding
540
+ $meta['bytes'] = $meta['bits'] / 8;
541
+ $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4)));
542
+ if ($meta['decal'] == 4) {
543
+ $meta['decal'] = 0;
544
+ }
545
+
546
+ // obtain imagesize
547
+ if ($meta['imagesize'] < 1) {
548
+ $meta['imagesize'] = $meta['filesize'] - $meta['offset'];
549
+ // in rare cases filesize is equal to offset so we need to read physical size
550
+ if ($meta['imagesize'] < 1) {
551
+ $meta['imagesize'] = @filesize($filename) - $meta['offset'];
552
+ if ($meta['imagesize'] < 1) {
553
+ trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING);
554
+ return false;
555
+ }
556
+ }
557
+ }
558
+
559
+ // calculate colors
560
+ $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors'];
561
+
562
+ // read color palette
563
+ $palette = array();
564
+ if ($meta['bits'] < 16) {
565
+ $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
566
+ // in rare cases the color value is signed
567
+ if ($palette[1] < 0) {
568
+ foreach ($palette as $i => $color) {
569
+ $palette[$i] = $color + 16777216;
570
+ }
571
+ }
572
+ }
573
+
574
+ // ignore extra bitmap headers
575
+ if ($meta['headersize'] > $bytes_read) {
576
+ fread($fh, $meta['headersize'] - $bytes_read);
577
+ }
578
+
579
+ // create gd image
580
+ $im = imagecreatetruecolor($meta['width'], $meta['height']);
581
+ $data = fread($fh, $meta['imagesize']);
582
+
583
+ // uncompress data
584
+ switch ($meta['compression']) {
585
+ case 1: $data = rle8_decode($data, $meta['width']); break;
586
+ case 2: $data = rle4_decode($data, $meta['width']); break;
587
+ }
588
+
589
+ $p = 0;
590
+ $vide = chr(0);
591
+ $y = $meta['height'] - 1;
592
+ $error = 'imagecreatefrombmp: ' . $filename . ' has not enough data!';
593
+
594
+ // loop through the image data beginning with the lower left corner
595
+ while ($y >= 0) {
596
+ $x = 0;
597
+ while ($x < $meta['width']) {
598
+ switch ($meta['bits']) {
599
+ case 32:
600
+ case 24:
601
+ if (!($part = substr($data, $p, 3 /*$meta['bytes']*/))) {
602
+ trigger_error($error, E_USER_WARNING);
603
+ return $im;
604
+ }
605
+ $color = unpack('V', $part . $vide);
606
+ break;
607
+ case 16:
608
+ if (!($part = substr($data, $p, 2 /*$meta['bytes']*/))) {
609
+ trigger_error($error, E_USER_WARNING);
610
+ return $im;
611
+ }
612
+ $color = unpack('v', $part);
613
+
614
+ if (empty($meta['rMask']) || $meta['rMask'] != 0xf800)
615
+ $color[1] = (($color[1] & 0x7c00) >> 7) * 65536 + (($color[1] & 0x03e0) >> 2) * 256 + (($color[1] & 0x001f) << 3); // 555
616
+ else
617
+ $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3); // 565
618
+ break;
619
+ case 8:
620
+ $color = unpack('n', $vide . substr($data, $p, 1));
621
+ $color[1] = $palette[ $color[1] + 1 ];
622
+ break;
623
+ case 4:
624
+ $color = unpack('n', $vide . substr($data, floor($p), 1));
625
+ $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
626
+ $color[1] = $palette[ $color[1] + 1 ];
627
+ break;
628
+ case 1:
629
+ $color = unpack('n', $vide . substr($data, floor($p), 1));
630
+ switch (($p * 8) % 8) {
631
+ case 0: $color[1] = $color[1] >> 7; break;
632
+ case 1: $color[1] = ($color[1] & 0x40) >> 6; break;
633
+ case 2: $color[1] = ($color[1] & 0x20) >> 5; break;
634
+ case 3: $color[1] = ($color[1] & 0x10) >> 4; break;
635
+ case 4: $color[1] = ($color[1] & 0x8 ) >> 3; break;
636
+ case 5: $color[1] = ($color[1] & 0x4 ) >> 2; break;
637
+ case 6: $color[1] = ($color[1] & 0x2 ) >> 1; break;
638
+ case 7: $color[1] = ($color[1] & 0x1 ); break;
639
+ }
640
+ $color[1] = $palette[ $color[1] + 1 ];
641
+ break;
642
+ default:
643
+ trigger_error('imagecreatefrombmp: ' . $filename . ' has ' . $meta['bits'] . ' bits and this is not supported!', E_USER_WARNING);
644
+ return false;
645
+ }
646
+ imagesetpixel($im, $x, $y, $color[1]);
647
+ $x++;
648
+ $p += $meta['bytes'];
649
+ }
650
+ $y--;
651
+ $p += $meta['decal'];
652
+ }
653
+ fclose($fh);
654
+ return $im;
655
+ } catch (Exception $e) {var_dump($e);}
656
+ }
657
+ }
658
+
659
+ /**
660
+ * getimagesize doesn't give a good size for 32bit BMP image v5
661
+ *
662
+ * @param string $filename
663
+ * @return array The same format as getimagesize($filename)
664
+ */
665
+ function dompdf_getimagesize($filename) {
666
+ static $cache = array();
667
+
668
+ if ( isset($cache[$filename]) ) {
669
+ return $cache[$filename];
670
+ }
671
+
672
+ list($width, $height, $type) = getimagesize($filename);
673
+
674
+ if ( $width == null || $height == null ) {
675
+ $data = file_get_contents($filename, null, null, 0, 26);
676
+
677
+ if ( substr($data, 0, 2) === "BM" ) {
678
+ $meta = unpack('vtype/Vfilesize/Vreserved/Voffset/Vheadersize/Vwidth/Vheight', $data);
679
+ $width = (int)$meta['width'];
680
+ $height = (int)$meta['height'];
681
+ $type = IMAGETYPE_BMP;
682
+ }
683
+ }
684
+
685
+ return $cache[$filename] = array($width, $height, $type);
686
+ }
687
+
688
+ /**
689
+ * Converts a CMYK color to RGB
690
+ *
691
+ * @param int $c
692
+ * @param int $m
693
+ * @param int $y
694
+ * @param int $k
695
+ * @return object
696
+ */
697
+ function cmyk_to_rgb($c, $m = null, $y = null, $k = null) {
698
+ if (is_array($c)) {
699
+ list($c, $m, $y, $k) = $c;
700
+ }
701
+
702
+ $c *= 255;
703
+ $m *= 255;
704
+ $y *= 255;
705
+ $k *= 255;
706
+
707
+ $r = (1 - round(2.55 * ($c+$k))) ;
708
+ $g = (1 - round(2.55 * ($m+$k))) ;
709
+ $b = (1 - round(2.55 * ($y+$k))) ;
710
+
711
+ if($r<0) $r = 0;
712
+ if($g<0) $g = 0;
713
+ if($b<0) $b = 0;
714
+
715
+ return array(
716
+ $r, $g, $b,
717
+ "r" => $r, "g" => $g, "b" => $b
718
+ );
719
+ }
720
+
721
+ function unichr($c) {
722
+ if ($c <= 0x7F) {
723
+ return chr($c);
724
+ } else if ($c <= 0x7FF) {
725
+ return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F);
726
+ } else if ($c <= 0xFFFF) {
727
+ return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F)
728
+ . chr(0x80 | $c & 0x3F);
729
+ } else if ($c <= 0x10FFFF) {
730
+ return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F)
731
+ . chr(0x80 | $c >> 6 & 0x3F)
732
+ . chr(0x80 | $c & 0x3F);
733
+ }
734
+ return false;
735
+ }
736
+
737
+ if ( !function_exists("date_default_timezone_get") ) {
738
+ function date_default_timezone_get() {
739
+ return "";
740
+ }
741
+
742
+ function date_default_timezone_set($timezone_identifier) {
743
+ return true;
744
+ }
745
+ }
746
+
747
+ /**
748
+ * Stores warnings in an array for display later
749
+ *
750
+ * This function allows warnings generated by the DomDocument parser
751
+ * and CSS loader ({@link Stylesheet}) to be captured and displayed
752
+ * later. Without this function, errors are displayed immediately and
753
+ * PDF streaming is impossible.
754
+ *
755
+ * @see http://www.php.net/manual/en/function.set-error_handler.php
756
+ *
757
+ * @param int $errno
758
+ * @param string $errstr
759
+ * @param string $errfile
760
+ * @param string $errline
761
+ */
762
+ function record_warnings($errno, $errstr, $errfile, $errline) {
763
+
764
+ if ( !($errno & (E_WARNING | E_NOTICE | E_USER_NOTICE | E_USER_WARNING )) ) // Not a warning or notice
765
+ throw new DOMPDF_Exception($errstr . " $errno");
766
+
767
+ global $_dompdf_warnings;
768
+ global $_dompdf_show_warnings;
769
+
770
+ if ( $_dompdf_show_warnings )
771
+ echo $errstr . "\n";
772
+
773
+ $_dompdf_warnings[] = $errstr;
774
+ }
775
+
776
+ /**
777
+ * Print a useful backtrace
778
+ */
779
+ function bt() {
780
+ if ( php_sapi_name() !== "cli")
781
+ echo("<pre>");
782
+
783
+ $bt = debug_backtrace();
784
+
785
+ array_shift($bt); // remove actual bt() call
786
+ echo "\n";
787
+
788
+ $i = 0;
789
+ foreach ($bt as $call) {
790
+ $file = basename($call["file"]) . " (" . $call["line"] . ")";
791
+ if ( isset($call["class"]) ) {
792
+ $func = $call["class"] . "->" . $call["function"] . "()";
793
+ } else {
794
+ $func = $call["function"] . "()";
795
+ }
796
+
797
+ echo "#" . str_pad($i, 2, " ", STR_PAD_RIGHT) . ": " . str_pad($file.":", 42) . " $func\n";
798
+ $i++;
799
+ }
800
+ echo "\n";
801
+
802
+ if ( php_sapi_name() !== "cli")
803
+ echo("</pre>");
804
+ }
805
+
806
+ /**
807
+ * Print debug messages
808
+ *
809
+ * @param string $type The type of debug messages to print
810
+ */
811
+ function dompdf_debug($type, $msg) {
812
+ global $_DOMPDF_DEBUG_TYPES, $_dompdf_show_warnings, $_dompdf_debug;
813
+ if ( isset($_DOMPDF_DEBUG_TYPES[$type]) && ($_dompdf_show_warnings || $_dompdf_debug) ) {
814
+ $arr = debug_backtrace();
815
+
816
+ echo basename($arr[0]["file"]) . " (" . $arr[0]["line"] ."): " . $arr[1]["function"] . ": ";
817
+ pre_r($msg);
818
+ }
819
+ }
820
+
821
+ if ( !function_exists("print_memusage") ) {
822
+ /**
823
+ * Dump memory usage
824
+ */
825
+ function print_memusage() {
826
+ global $memusage;
827
+ echo ("Memory Usage\n");
828
+ $prev = 0;
829
+ $initial = reset($memusage);
830
+ echo (str_pad("Initial:", 40) . $initial . "\n\n");
831
+
832
+ foreach ($memusage as $key=>$mem) {
833
+ $mem -= $initial;
834
+ echo (str_pad("$key:" , 40));
835
+ echo (str_pad("$mem", 12) . "(diff: " . ($mem - $prev) . ")\n");
836
+ $prev = $mem;
837
+ }
838
+
839
+ echo ("\n" . str_pad("Total:", 40) . memory_get_usage()) . "\n";
840
+ }
841
+ }
842
+
843
+ if ( !function_exists("enable_mem_profile") ) {
844
+ /**
845
+ * Initialize memory profiling code
846
+ */
847
+ function enable_mem_profile() {
848
+ global $memusage;
849
+ $memusage = array("Startup" => memory_get_usage());
850
+ register_shutdown_function("print_memusage");
851
+ }
852
+ }
853
+
854
+ if ( !function_exists("mark_memusage") ) {
855
+ /**
856
+ * Record the current memory usage
857
+ *
858
+ * @param string $location a meaningful location
859
+ */
860
+ function mark_memusage($location) {
861
+ global $memusage;
862
+ if ( isset($memusage) )
863
+ $memusage[$location] = memory_get_usage();
864
+ }
865
+ }
866
+
867
+ if ( !function_exists('sys_get_temp_dir')) {
868
+ /**
869
+ * Find the current system temporary directory
870
+ *
871
+ * @link http://us.php.net/manual/en/function.sys-get-temp-dir.php#85261
872
+ */
873
+ function sys_get_temp_dir() {
874
+ if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
875
+ if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
876
+ if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
877
+ $tempfile=tempnam(uniqid(rand(),TRUE),'');
878
+ if (file_exists($tempfile)) {
879
+ unlink($tempfile);
880
+ return realpath(dirname($tempfile));
881
+ }
882
+ }
883
+ }
884
+
885
+ if ( function_exists("memory_get_peak_usage") ) {
886
+ function DOMPDF_memory_usage(){
887
+ return memory_get_peak_usage(true);
888
+ }
889
+ }
890
+ else if ( function_exists("memory_get_usage") ) {
891
+ function DOMPDF_memory_usage(){
892
+ return memory_get_usage(true);
893
+ }
894
+ }
895
+ else {
896
+ function DOMPDF_memory_usage(){
897
+ return "N/A";
898
+ }
899
+ }
900
+
901
+ if ( function_exists("curl_init") ) {
902
+ function DOMPDF_fetch_url($url, &$headers = null) {
903
+ $ch = curl_init($url);
904
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
905
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
906
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
907
+ curl_setopt($ch, CURLOPT_HEADER, TRUE);
908
+
909
+ $data = curl_exec($ch);
910
+ $raw_headers = substr($data, 0, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
911
+ $headers = preg_split("/[\n\r]+/", trim($raw_headers));
912
+ $data = substr($data, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
913
+ curl_close($ch);
914
+
915
+ return $data;
916
+ }
917
+ }
918
+ else {
919
+ function DOMPDF_fetch_url($url, &$headers = null) {
920
+ $data = file_get_contents($url);
921
+ $headers = $http_response_header;
922
+
923
+ return $data;
924
+ }
925
+ }
926
+
927
+ /**
928
+ * Affect null to the unused objects
929
+ * @param mixed $object
930
+ */
931
+ if ( PHP_VERSION_ID < 50300 ) {
932
+ function clear_object(&$object) {
933
+ if ( is_object($object) ) {
934
+ foreach ($object as &$value) {
935
+ clear_object($value);
936
+ }
937
+ }
938
+
939
+ $object = null;
940
+ unset($object);
941
+ }
942
+ }
943
+ else {
944
+ function clear_object(&$object) {
945
+ // void
946
+ }
947
+ }
dompdf/include/gd_adapter.cls.php ADDED
@@ -0,0 +1,811 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: gd_adapter.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Image rendering interface
13
+ *
14
+ * Renders to an image format supported by GD (jpeg, gif, png, xpm).
15
+ * Not super-useful day-to-day but handy nonetheless
16
+ *
17
+ * @package dompdf
18
+ */
19
+ class GD_Adapter implements Canvas {
20
+
21
+ /**
22
+ * Resoure handle for the image
23
+ *
24
+ * @var resource
25
+ */
26
+ private $_img;
27
+
28
+ /**
29
+ * Image width in pixels
30
+ *
31
+ * @var int
32
+ */
33
+ private $_width;
34
+
35
+ /**
36
+ * Image height in pixels
37
+ *
38
+ * @var int
39
+ */
40
+ private $_height;
41
+
42
+ /**
43
+ * Current page number
44
+ *
45
+ * @var int
46
+ */
47
+ private $_page_number;
48
+
49
+ /**
50
+ * Total number of pages
51
+ *
52
+ * @var int
53
+ */
54
+ private $_page_count;
55
+
56
+ /**
57
+ * Image antialias factor
58
+ *
59
+ * @var float
60
+ */
61
+ private $_aa_factor;
62
+
63
+ /**
64
+ * Allocated colors
65
+ *
66
+ * @var array
67
+ */
68
+ private $_colors;
69
+
70
+ /**
71
+ * Background color
72
+ *
73
+ * @var int
74
+ */
75
+ private $_bg_color;
76
+
77
+ /**
78
+ * Class constructor
79
+ *
80
+ * @param mixed $size The size of image to create: array(x1,y1,x2,y2) or "letter", "legal", etc.
81
+ * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
82
+ * @param float $aa_factor Anti-aliasing factor, 1 for no AA
83
+ * @param array $bg_color Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1
84
+ */
85
+ function __construct($size, $orientation = "portrait", $aa_factor = 1, $bg_color = array(1,1,1,0) ) {
86
+
87
+ if ( !is_array($size) ) {
88
+ $size = strtolower($size);
89
+
90
+ if ( isset(CPDF_Adapter::$PAPER_SIZES[$size]) )
91
+ $size = CPDF_Adapter::$PAPER_SIZES[$size];
92
+ else
93
+ $size = CPDF_Adapter::$PAPER_SIZES["letter"];
94
+ }
95
+
96
+ if ( strtolower($orientation) === "landscape" ) {
97
+ list($size[2],$size[3]) = array($size[3],$size[2]);
98
+ }
99
+
100
+ if ( $aa_factor < 1 )
101
+ $aa_factor = 1;
102
+
103
+ $this->_aa_factor = $aa_factor;
104
+
105
+ $size[2] *= $aa_factor;
106
+ $size[3] *= $aa_factor;
107
+
108
+ $this->_width = $size[2] - $size[0];
109
+ $this->_height = $size[3] - $size[1];
110
+
111
+ $this->_img = imagecreatetruecolor($this->_width, $this->_height);
112
+
113
+ if ( is_null($bg_color) || !is_array($bg_color) ) {
114
+ // Pure white bg
115
+ $bg_color = array(1,1,1,0);
116
+ }
117
+
118
+ $this->_bg_color = $this->_allocate_color($bg_color);
119
+ imagealphablending($this->_img, true);
120
+ imagesavealpha($this->_img, true);
121
+ imagefill($this->_img, 0, 0, $this->_bg_color);
122
+
123
+ }
124
+
125
+ /**
126
+ * Return the GF image resource
127
+ *
128
+ * @return resource
129
+ */
130
+ function get_image() { return $this->_img; }
131
+
132
+ /**
133
+ * Return the image's width in pixels
134
+ *
135
+ * @return float
136
+ */
137
+ function get_width() { return $this->_width / $this->_aa_factor; }
138
+
139
+ /**
140
+ * Return the image's height in pixels
141
+ *
142
+ * @return float
143
+ */
144
+ function get_height() { return $this->_height / $this->_aa_factor; }
145
+
146
+ /**
147
+ * Returns the current page number
148
+ * @return int
149
+ */
150
+ function get_page_number() { return $this->_page_number; }
151
+
152
+ /**
153
+ * Returns the total number of pages in the document
154
+ * @return int
155
+ */
156
+ function get_page_count() { return $this->_page_count; }
157
+
158
+ /**
159
+ * Sets the current page number
160
+ *
161
+ * @param int $num
162
+ */
163
+ function set_page_number($num) { $this->_page_number = $num; }
164
+
165
+ /**
166
+ * Sets the page count
167
+ *
168
+ * @param int $count
169
+ */
170
+ function set_page_count($count) { $this->_page_count = $count; }
171
+
172
+ /**
173
+ * Sets the opacity
174
+ *
175
+ * @param $opacity
176
+ * @param $mode
177
+ */
178
+ function set_opacity($opacity, $mode = "Normal") {
179
+ // FIXME
180
+ }
181
+
182
+ /**
183
+ * Allocate a new color. Allocate with GD as needed and store
184
+ * previously allocated colors in $this->_colors.
185
+ *
186
+ * @param array $color The new current color
187
+ * @return int The allocated color
188
+ */
189
+ private function _allocate_color($color) {
190
+
191
+ if ( isset($color["c"]) ) {
192
+ $color = cmyk_to_rgb($color);
193
+ }
194
+
195
+ // Full opacity if no alpha set
196
+ if ( !isset($color[3]) )
197
+ $color[3] = 0;
198
+
199
+ list($r,$g,$b,$a) = $color;
200
+
201
+ $r *= 255;
202
+ $g *= 255;
203
+ $b *= 255;
204
+ $a *= 127;
205
+
206
+ // Clip values
207
+ $r = $r > 255 ? 255 : $r;
208
+ $g = $g > 255 ? 255 : $g;
209
+ $b = $b > 255 ? 255 : $b;
210
+ $a = $a > 127 ? 127 : $a;
211
+
212
+ $r = $r < 0 ? 0 : $r;
213
+ $g = $g < 0 ? 0 : $g;
214
+ $b = $b < 0 ? 0 : $b;
215
+ $a = $a < 0 ? 0 : $a;
216
+
217
+ $key = sprintf("#%02X%02X%02X%02X", $r, $g, $b, $a);
218
+
219
+ if ( isset($this->_colors[$key]) )
220
+ return $this->_colors[$key];
221
+
222
+ if ( $a != 0 )
223
+ $this->_colors[$key] = imagecolorallocatealpha($this->_img, $r, $g, $b, $a);
224
+ else
225
+ $this->_colors[$key] = imagecolorallocate($this->_img, $r, $g, $b);
226
+
227
+ return $this->_colors[$key];
228
+
229
+ }
230
+
231
+ /**
232
+ * Draws a line from x1,y1 to x2,y2
233
+ *
234
+ * See {@link Style::munge_color()} for the format of the color array.
235
+ * See {@link Cpdf::setLineStyle()} for a description of the format of the
236
+ * $style parameter (aka dash).
237
+ *
238
+ * @param float $x1
239
+ * @param float $y1
240
+ * @param float $x2
241
+ * @param float $y2
242
+ * @param array $color
243
+ * @param float $width
244
+ * @param array $style
245
+ */
246
+ function line($x1, $y1, $x2, $y2, $color, $width, $style = null) {
247
+
248
+ // Scale by the AA factor
249
+ $x1 *= $this->_aa_factor;
250
+ $y1 *= $this->_aa_factor;
251
+ $x2 *= $this->_aa_factor;
252
+ $y2 *= $this->_aa_factor;
253
+ $width *= $this->_aa_factor;
254
+
255
+ $c = $this->_allocate_color($color);
256
+
257
+ // Convert the style array if required
258
+ if ( !is_null($style) ) {
259
+ $gd_style = array();
260
+
261
+ if ( count($style) == 1 ) {
262
+ for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
263
+ $gd_style[] = $c;
264
+ }
265
+
266
+ for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
267
+ $gd_style[] = $this->_bg_color;
268
+ }
269
+
270
+ } else {
271
+
272
+ $i = 0;
273
+ foreach ($style as $length) {
274
+
275
+ if ( $i % 2 == 0 ) {
276
+ // 'On' pattern
277
+ for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
278
+ $gd_style[] = $c;
279
+
280
+ } else {
281
+ // Off pattern
282
+ for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
283
+ $gd_style[] = $this->_bg_color;
284
+
285
+ }
286
+ $i++;
287
+ }
288
+ }
289
+
290
+ imagesetstyle($this->_img, $gd_style);
291
+ $c = IMG_COLOR_STYLED;
292
+ }
293
+
294
+ imagesetthickness($this->_img, $width);
295
+
296
+ imageline($this->_img, $x1, $y1, $x2, $y2, $c);
297
+
298
+ }
299
+
300
+ /**
301
+ * Draws a rectangle at x1,y1 with width w and height h
302
+ *
303
+ * See {@link Style::munge_color()} for the format of the color array.
304
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
305
+ * parameter (aka dash)
306
+ *
307
+ * @param float $x1
308
+ * @param float $y1
309
+ * @param float $w
310
+ * @param float $h
311
+ * @param array $color
312
+ * @param float $width
313
+ * @param array $style
314
+ */
315
+ function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) {
316
+
317
+ // Scale by the AA factor
318
+ $x1 *= $this->_aa_factor;
319
+ $y1 *= $this->_aa_factor;
320
+ $w *= $this->_aa_factor;
321
+ $h *= $this->_aa_factor;
322
+
323
+ $c = $this->_allocate_color($color);
324
+
325
+ // Convert the style array if required
326
+ if ( !is_null($style) ) {
327
+ $gd_style = array();
328
+
329
+ foreach ($style as $length) {
330
+ for ($i = 0; $i < $length; $i++) {
331
+ $gd_style[] = $c;
332
+ }
333
+ }
334
+
335
+ imagesetstyle($this->_img, $gd_style);
336
+ $c = IMG_COLOR_STYLED;
337
+ }
338
+
339
+ imagesetthickness($this->_img, $width);
340
+
341
+ imagerectangle($this->_img, $x1, $y1, $x1 + $w, $y1 + $h, $c);
342
+
343
+ }
344
+
345
+ /**
346
+ * Draws a filled rectangle at x1,y1 with width w and height h
347
+ *
348
+ * See {@link Style::munge_color()} for the format of the color array.
349
+ *
350
+ * @param float $x1
351
+ * @param float $y1
352
+ * @param float $w
353
+ * @param float $h
354
+ * @param array $color
355
+ */
356
+ function filled_rectangle($x1, $y1, $w, $h, $color) {
357
+
358
+ // Scale by the AA factor
359
+ $x1 *= $this->_aa_factor;
360
+ $y1 *= $this->_aa_factor;
361
+ $w *= $this->_aa_factor;
362
+ $h *= $this->_aa_factor;
363
+
364
+ $c = $this->_allocate_color($color);
365
+
366
+ imagefilledrectangle($this->_img, $x1, $y1, $x1 + $w, $y1 + $h, $c);
367
+
368
+ }
369
+
370
+ /**
371
+ * Starts a clipping rectangle at x1,y1 with width w and height h
372
+ *
373
+ * @param float $x1
374
+ * @param float $y1
375
+ * @param float $w
376
+ * @param float $h
377
+ */
378
+ function clipping_rectangle($x1, $y1, $w, $h) {
379
+ // @todo
380
+ }
381
+
382
+ /**
383
+ * Ends the last clipping shape
384
+ */
385
+ function clipping_end() {
386
+ // @todo
387
+ }
388
+
389
+ function save() {
390
+ // @todo
391
+ }
392
+
393
+ function restore() {
394
+ // @todo
395
+ }
396
+
397
+ function rotate($angle, $x, $y) {
398
+ // @todo
399
+ }
400
+
401
+ function skew($angle_x, $angle_y, $x, $y) {
402
+ // @todo
403
+ }
404
+
405
+ function scale($s_x, $s_y, $x, $y) {
406
+ // @todo
407
+ }
408
+
409
+ function translate($t_x, $t_y) {
410
+ // @todo
411
+ }
412
+
413
+ function transform($a, $b, $c, $d, $e, $f) {
414
+ // @todo
415
+ }
416
+
417
+ /**
418
+ * Draws a polygon
419
+ *
420
+ * The polygon is formed by joining all the points stored in the $points
421
+ * array. $points has the following structure:
422
+ * <code>
423
+ * array(0 => x1,
424
+ * 1 => y1,
425
+ * 2 => x2,
426
+ * 3 => y2,
427
+ * ...
428
+ * );
429
+ * </code>
430
+ *
431
+ * See {@link Style::munge_color()} for the format of the color array.
432
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
433
+ * parameter (aka dash)
434
+ *
435
+ * @param array $points
436
+ * @param array $color
437
+ * @param float $width
438
+ * @param array $style
439
+ * @param bool $fill Fills the polygon if true
440
+ */
441
+ function polygon($points, $color, $width = null, $style = null, $fill = false) {
442
+
443
+ // Scale each point by the AA factor
444
+ foreach (array_keys($points) as $i)
445
+ $points[$i] *= $this->_aa_factor;
446
+
447
+ $c = $this->_allocate_color($color);
448
+
449
+ // Convert the style array if required
450
+ if ( !is_null($style) && !$fill ) {
451
+ $gd_style = array();
452
+
453
+ foreach ($style as $length) {
454
+ for ($i = 0; $i < $length; $i++) {
455
+ $gd_style[] = $c;
456
+ }
457
+ }
458
+
459
+ imagesetstyle($this->_img, $gd_style);
460
+ $c = IMG_COLOR_STYLED;
461
+ }
462
+
463
+ imagesetthickness($this->_img, $width);
464
+
465
+ if ( $fill )
466
+ imagefilledpolygon($this->_img, $points, count($points) / 2, $c);
467
+ else
468
+ imagepolygon($this->_img, $points, count($points) / 2, $c);
469
+
470
+ }
471
+
472
+ /**
473
+ * Draws a circle at $x,$y with radius $r
474
+ *
475
+ * See {@link Style::munge_color()} for the format of the color array.
476
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
477
+ * parameter (aka dash)
478
+ *
479
+ * @param float $x
480
+ * @param float $y
481
+ * @param float $r
482
+ * @param array $color
483
+ * @param float $width
484
+ * @param array $style
485
+ * @param bool $fill Fills the circle if true
486
+ */
487
+ function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) {
488
+
489
+ // Scale by the AA factor
490
+ $x *= $this->_aa_factor;
491
+ $y *= $this->_aa_factor;
492
+ $r *= $this->_aa_factor;
493
+
494
+ $c = $this->_allocate_color($color);
495
+
496
+ // Convert the style array if required
497
+ if ( !is_null($style) && !$fill ) {
498
+ $gd_style = array();
499
+
500
+ foreach ($style as $length) {
501
+ for ($i = 0; $i < $length; $i++) {
502
+ $gd_style[] = $c;
503
+ }
504
+ }
505
+
506
+ imagesetstyle($this->_img, $gd_style);
507
+ $c = IMG_COLOR_STYLED;
508
+ }
509
+
510
+ imagesetthickness($this->_img, $width);
511
+
512
+ if ( $fill )
513
+ imagefilledellipse($this->_img, $x, $y, $r, $r, $c);
514
+ else
515
+ imageellipse($this->_img, $x, $y, $r, $r, $c);
516
+
517
+ }
518
+
519
+ /**
520
+ * Add an image to the pdf.
521
+ *
522
+ * The image is placed at the specified x and y coordinates with the
523
+ * given width and height.
524
+ *
525
+ * @param string $img_url the path to the image
526
+ * @param string $img_type the type (e.g. extension) of the image
527
+ * @param float $x x position
528
+ * @param float $y y position
529
+ * @param int $w width (in pixels)
530
+ * @param int $h height (in pixels)
531
+ */
532
+ function image($img_url, $x, $y, $w, $h, $resolution = "normal") {
533
+ $img_type = Image_Cache::detect_type($img_url);
534
+ $img_ext = Image_Cache::type_to_ext($img_type);
535
+
536
+ if ( !$img_ext ) {
537
+ return;
538
+ }
539
+
540
+ $func = "imagecreatefrom$img_ext";
541
+ $src = @$func($img_url);
542
+
543
+ if ( !$src ) {
544
+ return; // Probably should add to $_dompdf_errors or whatever here
545
+ }
546
+
547
+ // Scale by the AA factor
548
+ $x *= $this->_aa_factor;
549
+ $y *= $this->_aa_factor;
550
+
551
+ $w *= $this->_aa_factor;
552
+ $h *= $this->_aa_factor;
553
+
554
+ $img_w = imagesx($src);
555
+ $img_h = imagesy($src);
556
+
557
+ imagecopyresampled($this->_img, $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h);
558
+
559
+ }
560
+
561
+ /**
562
+ * Writes text at the specified x and y coordinates
563
+ *
564
+ * See {@link Style::munge_color()} for the format of the color array.
565
+ *
566
+ * @param float $x
567
+ * @param float $y
568
+ * @param string $text the text to write
569
+ * @param string $font the font file to use
570
+ * @param float $size the font size, in points
571
+ * @param array $color
572
+ * @param float $adjust word spacing adjustment
573
+ * @param float $angle Text angle
574
+ */
575
+ function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_spacing = 0, $char_spacing = 0, $angle = 0) {
576
+
577
+ // Scale by the AA factor
578
+ $x *= $this->_aa_factor;
579
+ $y *= $this->_aa_factor;
580
+ $size *= $this->_aa_factor;
581
+
582
+ $h = $this->get_font_height($font, $size);
583
+ $c = $this->_allocate_color($color);
584
+
585
+ $text = mb_encode_numericentity($text, array(0x0080, 0xff, 0, 0xff), 'UTF-8');
586
+
587
+ $font = $this->get_ttf_file($font);
588
+
589
+ // FIXME: word spacing
590
+ @imagettftext($this->_img, $size, $angle, $x, $y + $h, $c, $font, $text);
591
+
592
+ }
593
+
594
+ function javascript($code) {
595
+ // Not implemented
596
+ }
597
+
598
+ /**
599
+ * Add a named destination (similar to <a name="foo">...</a> in html)
600
+ *
601
+ * @param string $anchorname The name of the named destination
602
+ */
603
+ function add_named_dest($anchorname) {
604
+ // Not implemented
605
+ }
606
+
607
+ /**
608
+ * Add a link to the pdf
609
+ *
610
+ * @param string $url The url to link to
611
+ * @param float $x The x position of the link
612
+ * @param float $y The y position of the link
613
+ * @param float $width The width of the link
614
+ * @param float $height The height of the link
615
+ */
616
+ function add_link($url, $x, $y, $width, $height) {
617
+ // Not implemented
618
+ }
619
+
620
+ /**
621
+ * Add meta information to the PDF
622
+ *
623
+ * @param string $label label of the value (Creator, Producer, etc.)
624
+ * @param string $value the text to set
625
+ */
626
+ function add_info($label, $value) {
627
+ // N/A
628
+ }
629
+
630
+ function set_default_view($view, $options = array()) {
631
+ // N/A
632
+ }
633
+
634
+ /**
635
+ * Calculates text size, in points
636
+ *
637
+ * @param string $text the text to be sized
638
+ * @param string $font the desired font
639
+ * @param float $size the desired font size
640
+ * @param float $spacing word spacing, if any
641
+ * @return float
642
+ */
643
+ function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0) {
644
+ $font = $this->get_ttf_file($font);
645
+
646
+ $text = mb_encode_numericentity($text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8');
647
+
648
+ // FIXME: word spacing
649
+ list($x1,,$x2) = @imagettfbbox($size, 0, $font, $text);
650
+ return $x2 - $x1;
651
+ }
652
+
653
+ function get_ttf_file($font) {
654
+ if ( strpos($font, '.ttf') === false )
655
+ $font .= ".ttf";
656
+
657
+ /*$filename = substr(strtolower(basename($font)), 0, -4);
658
+
659
+ if ( in_array($filename, DOMPDF::$native_fonts) ) {
660
+ return "arial.ttf";
661
+ }*/
662
+
663
+ return $font;
664
+ }
665
+
666
+ /**
667
+ * Calculates font height, in points
668
+ *
669
+ * @param string $font
670
+ * @param float $size
671
+ * @return float
672
+ */
673
+ function get_font_height($font, $size) {
674
+ $font = $this->get_ttf_file($font);
675
+
676
+ // FIXME: word spacing
677
+ list(,$y2,,,,$y1) = imagettfbbox($size, 0, $font, "MXjpqytfhl"); // Test string with ascenders, descenders and caps
678
+ return ($y2 - $y1) * DOMPDF_FONT_HEIGHT_RATIO;
679
+ }
680
+
681
+ function get_font_baseline($font, $size) {
682
+ return $this->get_font_height($font, $size) / DOMPDF_FONT_HEIGHT_RATIO;
683
+ }
684
+
685
+ /**
686
+ * Starts a new page
687
+ *
688
+ * Subsequent drawing operations will appear on the new page.
689
+ */
690
+ function new_page() {
691
+ $this->_page_number++;
692
+ $this->_page_count++;
693
+ }
694
+
695
+ function open_object(){
696
+ // N/A
697
+ }
698
+
699
+ function close_object(){
700
+ // N/A
701
+ }
702
+
703
+ function add_object(){
704
+ // N/A
705
+ }
706
+
707
+ function page_text(){
708
+ // N/A
709
+ }
710
+
711
+ /**
712
+ * Streams the image directly to the browser
713
+ *
714
+ * @param string $filename the name of the image file (ignored)
715
+ * @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
716
+ */
717
+ function stream($filename, $options = null) {
718
+
719
+ // Perform any antialiasing
720
+ if ( $this->_aa_factor != 1 ) {
721
+ $dst_w = $this->_width / $this->_aa_factor;
722
+ $dst_h = $this->_height / $this->_aa_factor;
723
+ $dst = imagecreatetruecolor($dst_w, $dst_h);
724
+ imagecopyresampled($dst, $this->_img, 0, 0, 0, 0,
725
+ $dst_w, $dst_h,
726
+ $this->_width, $this->_height);
727
+ } else {
728
+ $dst = $this->_img;
729
+ }
730
+
731
+ if ( !isset($options["type"]) )
732
+ $options["type"] = "png";
733
+
734
+ $type = strtolower($options["type"]);
735
+
736
+ header("Cache-Control: private");
737
+
738
+ switch ($type) {
739
+
740
+ case "jpg":
741
+ case "jpeg":
742
+ if ( !isset($options["quality"]) )
743
+ $options["quality"] = 75;
744
+
745
+ header("Content-type: image/jpeg");
746
+ imagejpeg($dst, '', $options["quality"]);
747
+ break;
748
+
749
+ case "png":
750
+ default:
751
+ header("Content-type: image/png");
752
+ imagepng($dst);
753
+ break;
754
+ }
755
+
756
+ if ( $this->_aa_factor != 1 )
757
+ imagedestroy($dst);
758
+ }
759
+
760
+ /**
761
+ * Returns the PNG as a string
762
+ *
763
+ * @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
764
+ * @return string
765
+ */
766
+ function output($options = null) {
767
+
768
+ if ( $this->_aa_factor != 1 ) {
769
+ $dst_w = $this->_width / $this->_aa_factor;
770
+ $dst_h = $this->_height / $this->_aa_factor;
771
+ $dst = imagecreatetruecolor($dst_w, $dst_h);
772
+ imagecopyresampled($dst, $this->_img, 0, 0, 0, 0,
773
+ $dst_w, $dst_h,
774
+ $this->_width, $this->_height);
775
+ } else {
776
+ $dst = $this->_img;
777
+ }
778
+
779
+ if ( !isset($options["type"]) )
780
+ $options["type"] = "png";
781
+
782
+ $type = $options["type"];
783
+
784
+ ob_start();
785
+
786
+ switch ($type) {
787
+
788
+ case "jpg":
789
+ case "jpeg":
790
+ if ( !isset($options["quality"]) )
791
+ $options["quality"] = 75;
792
+
793
+ imagejpeg($dst, '', $options["quality"]);
794
+ break;
795
+
796
+ case "png":
797
+ default:
798
+ imagepng($dst);
799
+ break;
800
+ }
801
+
802
+ $image = ob_get_clean();
803
+
804
+ if ( $this->_aa_factor != 1 )
805
+ imagedestroy($dst);
806
+
807
+ return $image;
808
+ }
809
+
810
+
811
+ }
dompdf/include/image_cache.cls.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien Ménager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: image_cache.cls.php 455 2012-01-19 19:25:18Z eclecticgeek@gmail.com $
10
+ */
11
+
12
+ /**
13
+ * Static class that resolves image urls and downloads and caches
14
+ * remote images if required.
15
+ *
16
+ * @access private
17
+ * @package dompdf
18
+ */
19
+ class Image_Cache {
20
+
21
+ /**
22
+ * Array of downloaded images. Cached so that identical images are
23
+ * not needlessly downloaded.
24
+ *
25
+ * @var array
26
+ */
27
+ static protected $_cache = array();
28
+
29
+ /**
30
+ * The url to the "broken image" used when images can't be loade
31
+ *
32
+ * @var string
33
+ */
34
+ public static $broken_image;
35
+
36
+ /**
37
+ * Resolve and fetch an image for use.
38
+ *
39
+ * @param string $url The url of the image
40
+ * @param string $proto Default protocol if none specified in $url
41
+ * @param string $host Default host if none specified in $url
42
+ * @param string $base_path Default path if none specified in $url
43
+ * @return array An array with two elements: The local path to the image and the image extension
44
+ */
45
+ static function resolve_url($url, $proto, $host, $base_path) {
46
+ $parsed_url = explode_url($url);
47
+ $message = null;
48
+
49
+ $remote = ($proto && $proto !== "file://") || ($parsed_url['protocol'] != "");
50
+
51
+ $datauri = strpos($parsed_url['protocol'], "data:") === 0;
52
+
53
+ try {
54
+
55
+ // Remote not allowed and is not DataURI
56
+ if ( !DOMPDF_ENABLE_REMOTE && $remote && !$datauri ) {
57
+ throw new DOMPDF_Image_Exception("DOMPDF_ENABLE_REMOTE is set to FALSE");
58
+ }
59
+
60
+ // Remote allowed or DataURI
61
+ else if ( DOMPDF_ENABLE_REMOTE && $remote || $datauri ) {
62
+ // Download remote files to a temporary directory
63
+ $full_url = build_url($proto, $host, $base_path, $url);
64
+
65
+ // From cache
66
+ if ( isset(self::$_cache[$full_url]) ) {
67
+ $resolved_url = self::$_cache[$full_url];
68
+ }
69
+
70
+ // From remote
71
+ else {
72
+ $resolved_url = tempnam(DOMPDF_TEMP_DIR, "ca_dompdf_img_");
73
+
74
+ if ($datauri) {
75
+ if ($parsed_data_uri = parse_data_uri($url)) {
76
+ $image = $parsed_data_uri['data'];
77
+ }
78
+ }
79
+ else {
80
+ $old_err = set_error_handler("record_warnings");
81
+ $image = file_get_contents($full_url);
82
+ restore_error_handler();
83
+ }
84
+
85
+ // Image not found or invalid
86
+ if ( strlen($image) == 0 ) {
87
+ $msg = ($datauri ? "Data-URI could not be parsed" : "Image not found");
88
+ throw new DOMPDF_Image_Exception($msg);
89
+ }
90
+
91
+ // Image found, put in cache and process
92
+ else {
93
+ //e.g. fetch.php?media=url.jpg&cache=1
94
+ //- Image file name might be one of the dynamic parts of the url, don't strip off!
95
+ //- a remote url does not need to have a file extension at all
96
+ //- local cached file does not have a matching file extension
97
+ //Therefore get image type from the content
98
+ file_put_contents($resolved_url, $image);
99
+ }
100
+ }
101
+ }
102
+
103
+ // Not remote, local image
104
+ else {
105
+ $resolved_url = build_url($proto, $host, $base_path, $url);
106
+ }
107
+
108
+
109
+ // Check if the local file is readable
110
+ if ( !is_readable($resolved_url) || !filesize($resolved_url) ) {
111
+ throw new DOMPDF_Image_Exception("Image not readable or empty");
112
+ }
113
+
114
+ // Check is the file is an image
115
+ else {
116
+ list($width, $height, $type) = dompdf_getimagesize($resolved_url);
117
+
118
+ // Known image type
119
+ if ( $width && $height && in_array($type, array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP)) ) {
120
+ //Don't put replacement image into cache - otherwise it will be deleted on cache cleanup.
121
+ //Only execute on successfull caching of remote image.
122
+ if ( DOMPDF_ENABLE_REMOTE && $remote ) {
123
+ self::$_cache[$full_url] = $resolved_url;
124
+ }
125
+ }
126
+
127
+ // Unknown image type
128
+ else {
129
+ throw new DOMPDF_Image_Exception("Image type unknown");
130
+ unlink($resolved_url);
131
+ }
132
+ }
133
+ }
134
+ catch(DOMPDF_Image_Exception $e) {
135
+ $resolved_url = self::$broken_image;
136
+ $type = IMAGETYPE_PNG;
137
+ $message = $e->getMessage()." \n $url";
138
+ }
139
+
140
+ return array($resolved_url, $type, $message);
141
+ }
142
+
143
+ /**
144
+ * Unlink all cached images (i.e. temporary images either downloaded
145
+ * or converted)
146
+ */
147
+ static function clear() {
148
+ if ( empty(self::$_cache) || DEBUGKEEPTEMP ) return;
149
+
150
+ foreach ( self::$_cache as $file ) {
151
+ if (DEBUGPNG) print "[clear unlink $file]";
152
+ unlink($file);
153
+ }
154
+ }
155
+
156
+ static function detect_type($file) {
157
+ list($width, $height, $type) = dompdf_getimagesize($file);
158
+ return $type;
159
+ }
160
+
161
+ static function type_to_ext($type) {
162
+ $image_types = array(
163
+ IMAGETYPE_GIF => "gif",
164
+ IMAGETYPE_PNG => "png",
165
+ IMAGETYPE_JPEG => "jpeg",
166
+ IMAGETYPE_BMP => "bmp",
167
+ );
168
+
169
+ return (isset($image_types[$type]) ? $image_types[$type] : null);
170
+ }
171
+
172
+ static function is_broken($url) {
173
+ return $url === self::$broken_image;
174
+ }
175
+ }
176
+
177
+ Image_Cache::$broken_image = DOMPDF_LIB_DIR . "/res/broken_image.png";
dompdf/include/image_frame_decorator.cls.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: image_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Decorates frames for image layout and rendering
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Image_Frame_Decorator extends Frame_Decorator {
18
+
19
+ /**
20
+ * The path to the image file (note that remote images are
21
+ * downloaded locally to DOMPDF_TEMP_DIR).
22
+ *
23
+ * @var string
24
+ */
25
+ protected $_image_url;
26
+
27
+ /**
28
+ * The image's file error message
29
+ *
30
+ * @var string
31
+ */
32
+ protected $_image_msg;
33
+
34
+ /**
35
+ * Class constructor
36
+ *
37
+ * @param Frame $frame the frame to decorate
38
+ * @param DOMPDF $dompdf the document's dompdf object (required to resolve relative & remote urls)
39
+ */
40
+ function __construct(Frame $frame, DOMPDF $dompdf) {
41
+ global $_dompdf_warnings;
42
+
43
+ parent::__construct($frame, $dompdf);
44
+ $url = $frame->get_node()->getAttribute("src");
45
+
46
+ //debugpng
47
+ if (DEBUGPNG) print '[__construct '.$url.']';
48
+
49
+ list($this->_image_url, $type, $this->_image_msg) = Image_Cache::resolve_url($url,
50
+ $dompdf->get_protocol(),
51
+ $dompdf->get_host(),
52
+ $dompdf->get_base_path());
53
+
54
+ if ( Image_Cache::is_broken($this->_image_url) &&
55
+ $alt = $frame->get_node()->getAttribute("alt") ) {
56
+ $style = $frame->get_style();
57
+ $style->width = (4/3)*Font_Metrics::get_text_width($alt, $style->font_family, $style->font_size, $style->word_spacing);
58
+ $style->height = Font_Metrics::get_font_height($style->font_family, $style->font_size);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Return the image's url
64
+ *
65
+ * @return string The url of this image
66
+ */
67
+ function get_image_url() {
68
+ return $this->_image_url;
69
+ }
70
+
71
+ /**
72
+ * Return the image's error message
73
+ *
74
+ * @return string The image's error message
75
+ */
76
+ function get_image_msg() {
77
+ return $this->_image_msg;
78
+ }
79
+
80
+ }
dompdf/include/image_frame_reflower.cls.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: image_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Image reflower class
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Image_Frame_Reflower extends Frame_Reflower {
18
+
19
+ function __construct(Image_Frame_Decorator $frame) {
20
+ parent::__construct($frame);
21
+ }
22
+
23
+ function reflow(Frame_Decorator $block = null) {
24
+ $this->_frame->position();
25
+
26
+ //FLOAT
27
+ //$frame = $this->_frame;
28
+ //$page = $frame->get_root();
29
+ //if (DOMPDF_ENABLE_CSS_FLOAT && $frame->get_style()->float !== "none" ) {
30
+ // $page->add_floating_frame($this);
31
+ //}
32
+ // Set the frame's width
33
+ $this->get_min_max_width();
34
+
35
+ if ( $block ) {
36
+ $block->add_frame_to_line($this->_frame);
37
+ }
38
+ }
39
+
40
+ function get_min_max_width() {
41
+ if (DEBUGPNG) {
42
+ // Determine the image's size. Time consuming. Only when really needed?
43
+ list($img_width, $img_height) = dompdf_getimagesize($this->_frame->get_image_url());
44
+ print "get_min_max_width() ".
45
+ $this->_frame->get_style()->width.' '.
46
+ $this->_frame->get_style()->height.';'.
47
+ $this->_frame->get_parent()->get_style()->width." ".
48
+ $this->_frame->get_parent()->get_style()->height.";".
49
+ $this->_frame->get_parent()->get_parent()->get_style()->width.' '.
50
+ $this->_frame->get_parent()->get_parent()->get_style()->height.';'.
51
+ $img_width. ' '.
52
+ $img_height.'|' ;
53
+ }
54
+
55
+ $style = $this->_frame->get_style();
56
+
57
+ //own style auto or invalid value: use natural size in px
58
+ //own style value: ignore suffix text including unit, use given number as px
59
+ //own style %: walk up parent chain until found available space in pt; fill available space
60
+ //
61
+ //special ignored unit: e.g. 10ex: e treated as exponent; x ignored; 10e completely invalid ->like auto
62
+
63
+ $width = ($style->width > 0 ? $style->width : 0);
64
+ if ( is_percent($width) ) {
65
+ $t = 0.0;
66
+ for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) {
67
+ $f_style = $f->get_style();
68
+ $t = $f_style->length_in_pt($f_style->width);
69
+ if ($t != 0) {
70
+ break;
71
+ }
72
+ }
73
+ $width = ((float)rtrim($width,"%") * $t)/100; //maybe 0
74
+ } elseif ( !mb_strpos($width, 'pt') ) {
75
+ // Don't set image original size if "%" branch was 0 or size not given.
76
+ // Otherwise aspect changed on %/auto combination for width/height
77
+ // Resample according to px per inch
78
+ // See also List_Bullet_Image_Frame_Decorator::__construct
79
+ $width = $style->length_in_pt($width);
80
+ }
81
+
82
+ $height = ($style->height > 0 ? $style->height : 0);
83
+ if ( is_percent($height) ) {
84
+ $t = 0.0;
85
+ for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) {
86
+ $f_style = $f->get_style();
87
+ $t = $f_style->length_in_pt($f_style->height);
88
+ if ($t != 0) {
89
+ break;
90
+ }
91
+ }
92
+ $height = ((float)rtrim($height,"%") * $t)/100; //maybe 0
93
+ } elseif ( !mb_strpos($height, 'pt') ) {
94
+ // Don't set image original size if "%" branch was 0 or size not given.
95
+ // Otherwise aspect changed on %/auto combination for width/height
96
+ // Resample according to px per inch
97
+ // See also List_Bullet_Image_Frame_Decorator::__construct
98
+ $height = $style->length_in_pt($height);
99
+ }
100
+
101
+ if ($width == 0 || $height == 0) {
102
+ // Determine the image's size. Time consuming. Only when really needed!
103
+ list($img_width, $img_height) = dompdf_getimagesize($this->_frame->get_image_url());
104
+
105
+ // don't treat 0 as error. Can be downscaled or can be catched elsewhere if image not readable.
106
+ // Resample according to px per inch
107
+ // See also List_Bullet_Image_Frame_Decorator::__construct
108
+ if ($width == 0 && $height == 0) {
109
+ $width = (float)($img_width * 72) / DOMPDF_DPI;
110
+ $height = (float)($img_height * 72) / DOMPDF_DPI;
111
+ } elseif ($height == 0 && $width != 0) {
112
+ $height = ($width / $img_width) * $img_height; //keep aspect ratio
113
+ } elseif ($width == 0 && $height != 0) {
114
+ $width = ($height / $img_height) * $img_width; //keep aspect ratio
115
+ }
116
+ }
117
+
118
+ if (DEBUGPNG) print $width.' '.$height.';';
119
+
120
+ $style->width = $width . "pt";
121
+ $style->height = $height . "pt";
122
+
123
+ return array( $width, $width, "min" => $width, "max" => $width);
124
+
125
+ }
126
+ }
dompdf/include/image_renderer.cls.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: image_renderer.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Image renderer
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Image_Renderer extends Block_Renderer {
18
+
19
+ function render(Frame $frame) {
20
+ // Render background & borders
21
+ $style = $frame->get_style();
22
+ $cb = $frame->get_containing_block();
23
+ list($x, $y, $w, $h) = $frame->get_border_box();
24
+
25
+ $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
26
+
27
+ if ( ($bg = $style->background_color) !== "transparent" )
28
+ $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
29
+
30
+ if ( ($url = $style->background_image) && $url !== "none" )
31
+ $this->_background_image($url, $x, $y, $w, $h, $style);
32
+
33
+ $this->_render_border($frame);
34
+ $this->_render_outline($frame);
35
+
36
+ list($x, $y) = $frame->get_padding_box();
37
+ $x += $style->length_in_pt($style->padding_left, $cb["w"]);
38
+ $y += $style->length_in_pt($style->padding_top, $cb["h"]);
39
+
40
+ $w = $style->length_in_pt($style->width, $cb["w"]);
41
+ $h = $style->length_in_pt($style->height, $cb["h"]);
42
+
43
+ $src = $frame->get_image_url();
44
+
45
+ if ( Image_Cache::is_broken($src) &&
46
+ $alt = $frame->get_node()->getAttribute("alt") ) {
47
+ $font = $style->font_family;
48
+ $size = $style->font_size;
49
+ $spacing = $style->word_spacing;
50
+ $this->_canvas->text($x, $y, $alt,
51
+ $font, $size,
52
+ $style->color, $spacing);
53
+ }
54
+ else {
55
+ $this->_canvas->image( $src, $x, $y, $w, $h, $style->image_resolution);
56
+ }
57
+
58
+ if ( $msg = $frame->get_image_msg() ) {
59
+ $parts = preg_split("/\s*\n\s*/", $msg);
60
+ $height = 10;
61
+ $_y = $alt ? $y+$h-count($parts)*$height : $y;
62
+
63
+ foreach($parts as $i => $_part) {
64
+ $this->_canvas->text($x, $_y + $i*$height, $_part, "times", $height*0.8, array(0.5, 0.5, 0.5));
65
+ }
66
+ }
67
+
68
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) {
69
+ $this->_debug_layout($frame->get_border_box(), "blue");
70
+ if (DEBUG_LAYOUT_PADDINGBOX) {
71
+ $this->_debug_layout($frame->get_padding_box(), "blue", array(0.5, 0.5));
72
+ }
73
+ }
74
+ }
75
+ }
dompdf/include/inline_frame_decorator.cls.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: inline_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Decorates frames for inline layout
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Inline_Frame_Decorator extends Frame_Decorator {
18
+
19
+ function __construct(Frame $frame, DOMPDF $dompdf) { parent::__construct($frame, $dompdf); }
20
+
21
+ function split($frame = null, $force_pagebreak = false) {
22
+
23
+ if ( is_null($frame) ) {
24
+ $this->get_parent()->split($this, $force_pagebreak);
25
+ return;
26
+ }
27
+
28
+ if ( $frame->get_parent() !== $this )
29
+ throw new DOMPDF_Exception("Unable to split: frame is not a child of this one.");
30
+
31
+ $split = $this->copy( $this->_frame->get_node()->cloneNode() );
32
+ $this->get_parent()->insert_child_after($split, $this);
33
+
34
+ // Unset the current node's right style properties
35
+ $style = $this->_frame->get_style();
36
+ $style->margin_right = 0;
37
+ $style->padding_right = 0;
38
+ $style->border_right_width = 0;
39
+
40
+ // Unset the split node's left style properties since we don't want them
41
+ // to propagate
42
+ $style = $split->get_style();
43
+ $style->margin_left = 0;
44
+ $style->padding_left = 0;
45
+ $style->border_left_width = 0;
46
+
47
+ //On continuation of inline element on next line,
48
+ //don't repeat non-vertically repeatble background images
49
+ //See e.g. in testcase image_variants, long desriptions
50
+ if ( ($url = $style->background_image) && $url !== "none"
51
+ && ($repeat = $style->background_repeat) && $repeat !== "repeat" && $repeat !== "repeat-y"
52
+ ) {
53
+ $style->background_image = "none";
54
+ }
55
+
56
+ // Add $frame and all following siblings to the new split node
57
+ $iter = $frame;
58
+ while ($iter) {
59
+ $frame = $iter;
60
+ $iter = $iter->get_next_sibling();
61
+ $frame->reset();
62
+ $split->append_child($frame);
63
+ }
64
+
65
+ $page_breaks = array("always", "left", "right");
66
+ $frame_style = $frame->get_style();
67
+ if( $force_pagebreak ||
68
+ in_array($frame_style->page_break_before, $page_breaks) ||
69
+ in_array($frame_style->page_break_after, $page_breaks) ) {
70
+
71
+ $this->get_parent()->split($split, true);
72
+ }
73
+ }
74
+
75
+ }
dompdf/include/inline_frame_reflower.cls.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: inline_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Reflows inline frames
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Inline_Frame_Reflower extends Frame_Reflower {
17
+
18
+ function __construct(Frame $frame) { parent::__construct($frame); }
19
+
20
+ //........................................................................
21
+
22
+ function reflow(Frame_Decorator $block = null) {
23
+ $frame = $this->_frame;
24
+
25
+ // Check if a page break is forced
26
+ $page = $frame->get_root();
27
+ $page->check_forced_page_break($frame);
28
+
29
+ if ( $page->is_full() )
30
+ return;
31
+
32
+ $style = $frame->get_style();
33
+
34
+ // Generated content
35
+ $this->_set_content();
36
+
37
+ $frame->position();
38
+
39
+ $cb = $frame->get_containing_block();
40
+
41
+ // Add our margin, padding & border to the first and last children
42
+ if ( ($f = $frame->get_first_child()) && $f instanceof Text_Frame_Decorator ) {
43
+ $f_style = $f->get_style();
44
+ $f_style->margin_left = $style->margin_left;
45
+ $f_style->padding_left = $style->padding_left;
46
+ $f_style->border_left = $style->border_left;
47
+ }
48
+
49
+ if ( ($l = $frame->get_last_child()) && $l instanceof Text_Frame_Decorator ) {
50
+ $l_style = $l->get_style();
51
+ $l_style->margin_right = $style->margin_right;
52
+ $l_style->padding_right = $style->padding_right;
53
+ $l_style->border_right = $style->border_right;
54
+ }
55
+
56
+ if ( $block ) {
57
+ $block->add_frame_to_line($this->_frame);
58
+ }
59
+
60
+ // Set the containing blocks and reflow each child. The containing
61
+ // block is not changed by line boxes.
62
+ foreach ( $frame->get_children() as $child ) {
63
+ $child->set_containing_block($cb);
64
+ $child->reflow($block);
65
+ }
66
+ }
67
+ }
dompdf/include/inline_positioner.cls.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: inline_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Positions inline frames
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Inline_Positioner extends Positioner {
17
+
18
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
19
+
20
+ //........................................................................
21
+
22
+ function position() {
23
+ /**
24
+ * Find our nearest block level parent and access its lines property.
25
+ * @var Block_Frame_Decorator
26
+ */
27
+ $p = $this->_frame->find_block_parent();
28
+
29
+ // Debugging code:
30
+
31
+ // pre_r("\nPositioning:");
32
+ // pre_r("Me: " . $this->_frame->get_node()->nodeName . " (" . spl_object_hash($this->_frame->get_node()) . ")");
33
+ // pre_r("Parent: " . $p->get_node()->nodeName . " (" . spl_object_hash($p->get_node()) . ")");
34
+
35
+ // End debugging
36
+
37
+ if ( !$p )
38
+ throw new DOMPDF_Exception("No block-level parent found. Not good.");
39
+
40
+ $f = $this->_frame;
41
+
42
+ $cb = $f->get_containing_block();
43
+ $line = $p->get_current_line_box();
44
+
45
+ // Skip the page break if in a fixed position element
46
+ $is_fixed = false;
47
+ while($f = $f->get_parent()) {
48
+ if($f->get_style()->position === "fixed") {
49
+ $is_fixed = true;
50
+ break;
51
+ }
52
+ }
53
+
54
+ $f = $this->_frame;
55
+
56
+ if ( !$is_fixed && $f->get_parent() &&
57
+ $f->get_parent() instanceof Inline_Frame_Decorator &&
58
+ $f->is_text_node() ) {
59
+
60
+ $min_max = $f->get_reflower()->get_min_max_width();
61
+
62
+ // If the frame doesn't fit in the current line, a line break occurs
63
+ if ( $min_max["min"] > ($cb["w"] - $line->left - $line->w - $line->right) ) {
64
+ $p->add_line();
65
+ }
66
+ }
67
+
68
+ $f->set_position($cb["x"] + $line->w, $line->y);
69
+
70
+ }
71
+ }
dompdf/include/inline_renderer.cls.php ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: inline_renderer.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Renders inline frames
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Inline_Renderer extends Abstract_Renderer {
17
+
18
+ //........................................................................
19
+
20
+ function render(Frame $frame) {
21
+ $style = $frame->get_style();
22
+
23
+ if ( !$frame->get_first_child() )
24
+ return; // No children, no service
25
+
26
+ // Draw the left border if applicable
27
+ $bp = $style->get_border_properties();
28
+ $widths = array($style->length_in_pt($bp["top"]["width"]),
29
+ $style->length_in_pt($bp["right"]["width"]),
30
+ $style->length_in_pt($bp["bottom"]["width"]),
31
+ $style->length_in_pt($bp["left"]["width"]));
32
+
33
+ // Draw the background & border behind each child. To do this we need
34
+ // to figure out just how much space each child takes:
35
+ list($x, $y) = $frame->get_first_child()->get_position();
36
+ $w = null;
37
+ $h = 0;
38
+ // $x += $widths[3];
39
+ // $y += $widths[0];
40
+
41
+ $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
42
+
43
+ $first_row = true;
44
+
45
+ foreach ($frame->get_children() as $child) {
46
+ list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box();
47
+
48
+ if ( !is_null($w) && $child_x < $x + $w ) {
49
+ //This branch seems to be supposed to being called on the first part
50
+ //of an inline html element, and the part after the if clause for the
51
+ //parts after a line break.
52
+ //But because $w initially mostly is 0, and gets updated only on the next
53
+ //round, this seem to be never executed and the common close always.
54
+
55
+ // The next child is on another line. Draw the background &
56
+ // borders on this line.
57
+
58
+ // Background:
59
+ if ( ($bg = $style->background_color) !== "transparent" )
60
+ $this->_canvas->filled_rectangle( $x, $y, $w, $h, $bg);
61
+
62
+ if ( ($url = $style->background_image) && $url !== "none" ) {
63
+ $this->_background_image($url, $x, $y, $w, $h, $style);
64
+ }
65
+
66
+ // If this is the first row, draw the left border
67
+ if ( $first_row ) {
68
+
69
+ if ( $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $bp["left"]["width"] > 0 ) {
70
+ $method = "_border_" . $bp["left"]["style"];
71
+ $this->$method($x, $y, $h + $widths[0] + $widths[2], $bp["left"]["color"], $widths, "left");
72
+ }
73
+ $first_row = false;
74
+ }
75
+
76
+ // Draw the top & bottom borders
77
+ if ( $bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $bp["top"]["width"] > 0 ) {
78
+ $method = "_border_" . $bp["top"]["style"];
79
+ $this->$method($x, $y, $w + $widths[1] + $widths[3], $bp["top"]["color"], $widths, "top");
80
+ }
81
+
82
+ if ( $bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $bp["bottom"]["width"] > 0 ) {
83
+ $method = "_border_" . $bp["bottom"]["style"];
84
+ $this->$method($x, $y + $h + $widths[0] + $widths[2], $w + $widths[1] + $widths[3], $bp["bottom"]["color"], $widths, "bottom");
85
+ }
86
+
87
+ // Handle anchors & links
88
+ $link_node = null;
89
+ if ( $frame->get_node()->nodeName === "a" ) {
90
+ $link_node = $frame->get_node();
91
+ }
92
+ else if ( $frame->get_parent()->get_node()->nodeName === "a" ){
93
+ $link_node = $frame->get_parent()->get_node();
94
+ }
95
+
96
+ if ( $link_node && $href = $link_node->getAttribute("href") ) {
97
+ $this->_canvas->add_link($href, $x, $y, $w, $h);
98
+ }
99
+
100
+ $x = $child_x;
101
+ $y = $child_y;
102
+ $w = $child_w;
103
+ $h = $child_h;
104
+ continue;
105
+ }
106
+
107
+ if ( is_null($w) )
108
+ $w = $child_w;
109
+ else
110
+ $w += $child_w;
111
+
112
+ $h = max($h, $child_h);
113
+ }
114
+
115
+
116
+ // Handle the last child
117
+ if ( ($bg = $style->background_color) !== "transparent" )
118
+ $this->_canvas->filled_rectangle( $x + $widths[3], $y + $widths[0], $w, $h, $bg);
119
+
120
+ //On continuation lines (after line break) of inline elements, the style got copied.
121
+ //But a non repeatable background image should not be repeated on the next line.
122
+ //But removing the background image above has never an effect, and removing it below
123
+ //removes it always, even on the initial line.
124
+ //Need to handle it elsewhere, e.g. on certain ...clone()... usages.
125
+ // Repeat not given: default is Style::__construct
126
+ // ... && (!($repeat = $style->background_repeat) || $repeat === "repeat" ...
127
+ //different position? $this->_background_image($url, $x, $y, $w, $h, $style);
128
+ if ( ($url = $style->background_image) && $url !== "none" )
129
+ $this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style);
130
+
131
+ // Add the border widths
132
+ $w += $widths[1] + $widths[3];
133
+ $h += $widths[0] + $widths[2];
134
+
135
+ // make sure the border and background start inside the left margin
136
+ $left_margin = $style->length_in_pt($style->margin_left);
137
+ $x += $left_margin;
138
+
139
+ // If this is the first row, draw the left border too
140
+ if ( $first_row && $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $widths[3] > 0 ) {
141
+ $method = "_border_" . $bp["left"]["style"];
142
+ $this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left");
143
+ }
144
+
145
+ // Draw the top & bottom borders
146
+ if ( $bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $widths[0] > 0 ) {
147
+ $method = "_border_" . $bp["top"]["style"];
148
+ $this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top");
149
+ }
150
+
151
+ if ( $bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $widths[2] > 0 ) {
152
+ $method = "_border_" . $bp["bottom"]["style"];
153
+ $this->$method($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
154
+ }
155
+
156
+ // pre_var_dump(get_class($frame->get_next_sibling()));
157
+ // $last_row = get_class($frame->get_next_sibling()) !== 'Inline_Frame_Decorator';
158
+ // Draw the right border if this is the last row
159
+ if ( $bp["right"]["style"] !== "none" && $bp["right"]["color"] !== "transparent" && $widths[1] > 0 ) {
160
+ $method = "_border_" . $bp["right"]["style"];
161
+ $this->$method($x + $w, $y, $h, $bp["right"]["color"], $widths, "right");
162
+ }
163
+
164
+ // Only two levels of links frames
165
+ $link_node = null;
166
+ if ( $frame->get_node()->nodeName === "a" ) {
167
+ $link_node = $frame->get_node();
168
+
169
+ if ( ($name = $link_node->getAttribute("name")) || ($name = $link_node->getAttribute("id")) ) {
170
+ $this->_canvas->add_named_dest($name);
171
+ }
172
+ }
173
+
174
+ if ( $frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a" ){
175
+ $link_node = $frame->get_parent()->get_node();
176
+ }
177
+
178
+ // Handle anchors & links
179
+ if ( $link_node ) {
180
+ if ( $href = $link_node->getAttribute("href") )
181
+ $this->_canvas->add_link($href, $x, $y, $w, $h);
182
+ }
183
+
184
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_INLINE) {
185
+ $this->_debug_layout($child->get_border_box(), "blue");
186
+ if (DEBUG_LAYOUT_PADDINGBOX) {
187
+ $this->_debug_layout($child->get_padding_box(), "blue", array(0.5, 0.5));
188
+ }
189
+ }
190
+ }
191
+ }
dompdf/include/javascript_embedder.cls.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Fabien M�nager <fabien.menager@gmail.com>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: javascript_embedder.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Embeds Javascript into the PDF document
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Javascript_Embedder {
17
+
18
+ /**
19
+ * @var DOMPDF
20
+ */
21
+ protected $_dompdf;
22
+
23
+ function __construct(DOMPDF $dompdf) {
24
+ $this->_dompdf = $dompdf;
25
+ }
26
+
27
+ function insert($code) {
28
+ $this->_dompdf->get_canvas()->javascript($code);
29
+ }
30
+
31
+ function render($frame) {
32
+ if ( !DOMPDF_ENABLE_JAVASCRIPT )
33
+ return;
34
+
35
+ $this->insert($frame->get_node()->nodeValue);
36
+ }
37
+ }
dompdf/include/line_box.cls.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Fabien M�nager <fabien.menager@gmail.com>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: line_box.cls.php 471 2012-02-06 21:59:10Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * The line box class
12
+ *
13
+ * This class represents a line box
14
+ * http://www.w3.org/TR/CSS2/visuren.html#line-box
15
+ *
16
+ * @access protected
17
+ * @package dompdf
18
+ */
19
+ class Line_Box {
20
+
21
+ /**
22
+ * @var Block_Frame_Decorator
23
+ */
24
+ protected $_block_frame;
25
+
26
+ /**
27
+ * @var array
28
+ */
29
+ protected $_frames = array();
30
+
31
+ /**
32
+ * @var integer
33
+ */
34
+ public $wc = 0;
35
+
36
+ /**
37
+ * @var float
38
+ */
39
+ public $y = null;
40
+
41
+ /**
42
+ * @var float
43
+ */
44
+ public $w = 0.0;
45
+
46
+ /**
47
+ * @var float
48
+ */
49
+ public $h = 0.0;
50
+
51
+ /**
52
+ * @var float
53
+ */
54
+ public $left = 0.0;
55
+
56
+ /**
57
+ * @var float
58
+ */
59
+ public $right = 0.0;
60
+
61
+ /**
62
+ * @var Frame
63
+ */
64
+ public $tallest_frame = null;
65
+
66
+ public $floating_blocks = array();
67
+
68
+ /**
69
+ * @var bool
70
+ */
71
+ public $br = false;
72
+
73
+ /**
74
+ * Class constructor
75
+ *
76
+ * @param Block_Frame_Decorator $frame the Block_Frame_Decorator containing this line
77
+ */
78
+ function __construct(Block_Frame_Decorator $frame, $y = 0) {
79
+ $this->_block_frame = $frame;
80
+ $this->_frames = array();
81
+ $this->y = $y;
82
+
83
+ $this->get_float_offsets();
84
+ }
85
+
86
+ /**
87
+ * Returns the floating elements inside the first floating parent
88
+ * @param $root
89
+ */
90
+ function get_floats_inside($root) {
91
+ // Find nearest floating element
92
+ $p = $this->_block_frame;
93
+ while( $p->get_style()->float === "none" ) {
94
+ $parent = $p->get_parent();
95
+
96
+ if (!$parent) {
97
+ break;
98
+ }
99
+
100
+ $p = $parent;
101
+ }
102
+
103
+ $floating_frames = $root->get_floating_frames();
104
+
105
+ if ( $p == $root ) {
106
+ return $floating_frames;
107
+ }
108
+
109
+ $parent = $p;
110
+
111
+ $childs = array();
112
+
113
+ foreach ($floating_frames as $_floating) {
114
+ $p = $_floating->get_parent();
115
+
116
+ while(($p = $p->get_parent()) && $p !== $parent);
117
+
118
+ if ($p) {
119
+ $childs[] = $p;
120
+ }
121
+ }
122
+
123
+ return $childs;
124
+
125
+ }
126
+
127
+ function get_float_offsets() {
128
+ if ( !DOMPDF_ENABLE_CSS_FLOAT ) {
129
+ return;
130
+ }
131
+
132
+ static $anti_infinite_loop = 500; // FIXME smelly hack
133
+
134
+ $reflower = $this->_block_frame->get_reflower();
135
+
136
+ if ( !$reflower ) return;
137
+
138
+ $cb_w = null;
139
+
140
+ $block = $this->_block_frame;
141
+ $root = $block->get_root();
142
+ $floating_frames = $this->get_floats_inside($root);
143
+
144
+ foreach ( $floating_frames as $child_key => $floating_frame ) {
145
+ $id = $floating_frame->get_id();
146
+
147
+ if ( isset($this->floating_blocks[$id]) ) {
148
+ continue;
149
+ }
150
+
151
+ $floating_style = $floating_frame->get_style();
152
+
153
+ $clear = $floating_style->clear;
154
+ $float = $floating_style->float;
155
+
156
+ $floating_width = $floating_frame->get_margin_width();
157
+
158
+ if (!$cb_w) {
159
+ $cb_w = $floating_frame->get_containing_block("w");
160
+ }
161
+
162
+ $line_w = $this->get_width();
163
+
164
+ if (!$floating_frame->_float_next_line && ($cb_w <= $line_w + $floating_width) && ($cb_w > $line_w) ) {
165
+ $floating_frame->_float_next_line = true;
166
+ continue;
167
+ }
168
+
169
+ // If the child is still shifted by the floating element
170
+ if ( $anti_infinite_loop-- > 0 &&
171
+ $floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y &&
172
+ $block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x")
173
+ ) {
174
+ if ( $float === "left" )
175
+ $this->left += $floating_width;
176
+ else
177
+ $this->right += $floating_width;
178
+
179
+ $this->floating_blocks[$id] = true;
180
+ }
181
+
182
+ // else, the floating element won't shift anymore
183
+ else {
184
+ $root->remove_floating_frame($child_key);
185
+ }
186
+ }
187
+ }
188
+
189
+ function get_width(){
190
+ return $this->left + $this->w + $this->right;
191
+ }
192
+
193
+ /**
194
+ * @return Block_Frame_Decorator
195
+ */
196
+ function get_block_frame() { return $this->_block_frame; }
197
+
198
+ /**
199
+ * @return array
200
+ */
201
+ function &get_frames() { return $this->_frames; }
202
+
203
+ function add_frame(Frame $frame) {
204
+ $this->_frames[] = $frame;
205
+ }
206
+
207
+ function __toString(){
208
+ $props = array("wc", "y", "w", "h", "left", "right", "br");
209
+ $s = "";
210
+ foreach($props as $prop) {
211
+ $s .= "$prop: ".$this->$prop."\n";
212
+ }
213
+ $s .= count($this->_frames)." frames\n";
214
+ return $s;
215
+ }
216
+ /*function __get($prop) {
217
+ if (!isset($this->{"_$prop"})) return;
218
+ return $this->{"_$prop"};
219
+ }*/
220
+ }
221
+
222
+ /*
223
+ class LineBoxList implements Iterator {
224
+ private $_p = 0;
225
+ private $_lines = array();
226
+
227
+ }
228
+ */
dompdf/include/list_bullet_frame_decorator.cls.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: list_bullet_frame_decorator.cls.php 451 2012-01-14 14:54:23Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Decorates frames for list bullet rendering
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class List_Bullet_Frame_Decorator extends Frame_Decorator {
18
+
19
+ const BULLET_PADDING = 1; // Distance from bullet to text in pt
20
+ // As fraction of font size (including descent). See also DECO_THICKNESS.
21
+ const BULLET_THICKNESS = 0.04; // Thickness of bullet outline. Screen: 0.08, print: better less, e.g. 0.04
22
+ const BULLET_DESCENT = 0.3; //descent of font below baseline. Todo: Guessed for now.
23
+ const BULLET_SIZE = 0.35; // bullet diameter. For now 0.5 of font_size without descent.
24
+
25
+ static $BULLET_TYPES = array("disc", "circle", "square");
26
+
27
+ //........................................................................
28
+
29
+ function __construct(Frame $frame, DOMPDF $dompdf) {
30
+ parent::__construct($frame, $dompdf);
31
+ }
32
+
33
+ function get_margin_width() {
34
+ $style = $this->_frame->get_style();
35
+
36
+ // Small hack to prevent extra indenting of list text on list_style_position === "inside"
37
+ // and on suppressed bullet
38
+ if ( $style->list_style_position === "outside" ||
39
+ $style->list_style_type === "none" ) {
40
+ return 0;
41
+ }
42
+
43
+ return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
44
+ }
45
+
46
+ //hits only on "inset" lists items, to increase height of box
47
+ function get_margin_height() {
48
+ $style = $this->_frame->get_style();
49
+
50
+ if ( $style->list_style_type === "none" ) {
51
+ return 0;
52
+ }
53
+
54
+ return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
55
+ }
56
+
57
+ function get_width() {
58
+ return $this->get_margin_height();
59
+ }
60
+
61
+ function get_height() {
62
+ return $this->get_margin_height();
63
+ }
64
+
65
+ //........................................................................
66
+ }
dompdf/include/list_bullet_frame_reflower.cls.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: list_bullet_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Reflows list bullets
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class List_Bullet_Frame_Reflower extends Frame_Reflower {
17
+
18
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
19
+
20
+ //........................................................................
21
+
22
+ function reflow(Frame_Decorator $block = null) {
23
+ $style = $this->_frame->get_style();
24
+
25
+ $style->width = $this->_frame->get_width();
26
+ $this->_frame->position();
27
+
28
+ if ( $style->list_style_position === "inside" ) {
29
+ $p = $this->_frame->find_block_parent();
30
+ $p->add_frame_to_line($this->_frame);
31
+ }
32
+
33
+ }
34
+ }
dompdf/include/list_bullet_image_frame_decorator.cls.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: list_bullet_image_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Decorates frames for list bullets with custom images
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class List_Bullet_Image_Frame_Decorator extends Frame_Decorator {
18
+
19
+ /**
20
+ * The underlying image frame
21
+ *
22
+ * @var Image_Frame_Decorator
23
+ */
24
+ protected $_img;
25
+
26
+ /**
27
+ * The image's width in pixels
28
+ *
29
+ * @var int
30
+ */
31
+ protected $_width;
32
+
33
+ /**
34
+ * The image's height in pixels
35
+ *
36
+ * @var int
37
+ */
38
+ protected $_height;
39
+
40
+ /**
41
+ * Class constructor
42
+ *
43
+ * @param Frame $frame the bullet frame to decorate
44
+ * @param DOMPDF $dompdf the document's dompdf object
45
+ */
46
+ function __construct(Frame $frame, DOMPDF $dompdf) {
47
+ $style = $frame->get_style();
48
+ $url = $style->list_style_image;
49
+ $frame->get_node()->setAttribute("src", $url);
50
+ $this->_img = new Image_Frame_Decorator($frame, $dompdf);
51
+ parent::__construct($this->_img, $dompdf);
52
+ list($width, $height) = dompdf_getimagesize($this->_img->get_image_url());
53
+
54
+ // Resample the bullet image to be consistent with 'auto' sized images
55
+ // See also Image_Frame_Reflower::get_min_max_width
56
+ // Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
57
+ $this->_width = (((float)rtrim($width, "px")) * 72) / DOMPDF_DPI;
58
+ $this->_height = (((float)rtrim($height, "px")) * 72) / DOMPDF_DPI;
59
+
60
+ //If an image is taller as the containing block/box, the box should be extended.
61
+ //Neighbour elements are overwriting the overlapping image areas.
62
+ //Todo: Where can the box size be extended?
63
+ //Code below has no effect.
64
+ //See block_frame_reflower _calculate_restricted_height
65
+ //See generated_frame_reflower, Dompdf:render() "list-item", "-dompdf-list-bullet"S.
66
+ //Leave for now
67
+ //if ($style->min_height < $this->_height ) {
68
+ // $style->min_height = $this->_height;
69
+ //}
70
+ //$style->height = "auto";
71
+ }
72
+
73
+ /**
74
+ * Return the bullet's width
75
+ *
76
+ * @return int
77
+ */
78
+ function get_width() {
79
+ //ignore image width, use same width as on predefined bullet List_Bullet_Frame_Decorator
80
+ //for proper alignment of bullet image and text. Allow image to not fitting on left border.
81
+ //This controls the distance between bullet image and text
82
+ //return $this->_width;
83
+ return $this->_frame->get_style()->get_font_size()*List_Bullet_Frame_Decorator::BULLET_SIZE +
84
+ 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
85
+ }
86
+
87
+ /**
88
+ * Return the bullet's height
89
+ *
90
+ * @return int
91
+ */
92
+ function get_height() {
93
+ //based on image height
94
+ return $this->_height;
95
+ }
96
+
97
+ /**
98
+ * Override get_margin_width
99
+ *
100
+ * @return int
101
+ */
102
+ function get_margin_width() {
103
+ //ignore image width, use same width as on predefined bullet List_Bullet_Frame_Decorator
104
+ //for proper alignment of bullet image and text. Allow image to not fitting on left border.
105
+ //This controls the extra indentation of text to make room for the bullet image.
106
+ //Here use actual image size, not predefined bullet size
107
+ //return $this->_frame->get_style()->get_font_size()*List_Bullet_Frame_Decorator::BULLET_SIZE +
108
+ // 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
109
+
110
+ // Small hack to prevent indenting of list text
111
+ // Image Might not exist, then position like on list_bullet_frame_decorator fallback to none.
112
+ if ( $this->_frame->get_style()->list_style_position === "outside" ||
113
+ $this->_width == 0)
114
+ return 0;
115
+ //This aligns the "inside" image position with the text.
116
+ //The text starts to the right of the image.
117
+ //Between the image and the text there is an added margin of image width.
118
+ //Where this comes from is unknown.
119
+ //The corresponding List_Bullet_Frame_Decorator sets a smaller margin. bullet size?
120
+ return $this->_width + 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
121
+ }
122
+
123
+ /**
124
+ * Override get_margin_height()
125
+ *
126
+ * @return int
127
+ */
128
+ function get_margin_height() {
129
+ //Hits only on "inset" lists items, to increase height of box
130
+ //based on image height
131
+ return $this->_height + 2 * List_Bullet_Frame_Decorator::BULLET_PADDING;
132
+ }
133
+
134
+ /**
135
+ * Return image url
136
+ *
137
+ * @return string
138
+ */
139
+ function get_image_url() {
140
+ return $this->_img->get_image_url();
141
+ }
142
+
143
+ }
dompdf/include/list_bullet_positioner.cls.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: list_bullet_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Positions list bullets
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class List_Bullet_Positioner extends Positioner {
18
+
19
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
20
+
21
+ //........................................................................
22
+
23
+ function position() {
24
+
25
+ // Bullets & friends are positioned an absolute distance to the left of
26
+ // the content edge of their parent element
27
+ $cb = $this->_frame->get_containing_block();
28
+
29
+ // Note: this differs from most frames in that we must position
30
+ // ourselves after determining our width
31
+ $x = $cb["x"] - $this->_frame->get_width();
32
+
33
+ $p = $this->_frame->find_block_parent();
34
+
35
+ $y = $p->get_current_line_box()->y;
36
+
37
+ // This is a bit of a hack...
38
+ $n = $this->_frame->get_next_sibling();
39
+ if ( $n ) {
40
+ $style = $n->get_style();
41
+ $line_height = $style->length_in_pt($style->line_height, $style->get_font_size());
42
+ $offset = $style->length_in_pt($line_height, $n->get_containing_block("h")) - $this->_frame->get_height();
43
+ $y += $offset / 2;
44
+ }
45
+
46
+ // Now the position is the left top of the block which should be marked with the bullet.
47
+ // We tried to find out the y of the start of the first text character within the block.
48
+ // But the top margin/padding does not fit, neither from this nor from the next sibling
49
+ // The "bit of a hack" above does not work also.
50
+
51
+ // Instead let's position the bullet vertically centered to the block which should be marked.
52
+ // But for get_next_sibling() the get_containing_block is all zero, and for find_block_parent()
53
+ // the get_containing_block is paper width and the entire list as height.
54
+
55
+ // if ($p) {
56
+ // //$cb = $n->get_containing_block();
57
+ // $cb = $p->get_containing_block();
58
+ // $y += $cb["h"]/2;
59
+ // print 'cb:'.$cb["x"].':'.$cb["y"].':'.$cb["w"].':'.$cb["h"].':';
60
+ // }
61
+
62
+ // Todo:
63
+ // For now give up on the above. Use Guesswork with font y-pos in the middle of the line spacing
64
+
65
+ /*$style = $p->get_style();
66
+ $font_size = $style->get_font_size();
67
+ $line_height = $style->length_in_pt($style->line_height, $font_size);
68
+ $y += ($line_height - $font_size) / 2; */
69
+
70
+ //Position is x-end y-top of character position of the bullet.
71
+ $this->_frame->set_position($x, $y);
72
+
73
+ }
74
+ }
dompdf/include/list_bullet_renderer.cls.php ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: list_bullet_renderer.cls.php 468 2012-02-05 10:51:40Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Renders list bullets
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class List_Bullet_Renderer extends Abstract_Renderer {
18
+ static function get_counter_chars($type) {
19
+ static $cache = array();
20
+
21
+ if ( isset($cache[$type]) ) {
22
+ return $cache[$type];
23
+ }
24
+
25
+ $uppercase = false;
26
+ $text = "";
27
+
28
+ switch ($type) {
29
+ case "decimal-leading-zero":
30
+ case "decimal":
31
+ case "1":
32
+ return "0123456789";
33
+
34
+ case "upper-alpha":
35
+ case "upper-latin":
36
+ case "A":
37
+ $uppercase = true;
38
+ case "lower-alpha":
39
+ case "lower-latin":
40
+ case "a":
41
+ $text = "abcdefghijklmnopqrstuvwxyz";
42
+ break;
43
+
44
+ case "upper-roman":
45
+ case "I":
46
+ $uppercase = true;
47
+ case "lower-roman":
48
+ case "i":
49
+ $text = "ivxlcdm";
50
+ break;
51
+
52
+ case "lower-greek":
53
+ for($i = 0; $i < 24; $i++) {
54
+ $text .= unichr($i+944);
55
+ }
56
+ break;
57
+ }
58
+
59
+ if ( $uppercase ) {
60
+ $text = strtoupper($text);
61
+ }
62
+
63
+ return $cache[$type] = "$text.";
64
+ }
65
+
66
+ //........................................................................
67
+ private function make_counter($n, $type, $pad = null){
68
+ $n = intval($n);
69
+ $text = "";
70
+ $uppercase = false;
71
+
72
+ switch ($type) {
73
+ case "decimal-leading-zero":
74
+ case "decimal":
75
+ case "1":
76
+ if ($pad)
77
+ $text = str_pad($n, $pad, "0", STR_PAD_LEFT);
78
+ else
79
+ $text = $n;
80
+ break;
81
+
82
+ case "upper-alpha":
83
+ case "upper-latin":
84
+ case "A":
85
+ $uppercase = true;
86
+ case "lower-alpha":
87
+ case "lower-latin":
88
+ case "a":
89
+ $text = chr( ($n % 26) + ord('a') - 1);
90
+ break;
91
+
92
+ case "upper-roman":
93
+ case "I":
94
+ $uppercase = true;
95
+ case "lower-roman":
96
+ case "i":
97
+ $text = dec2roman($n);
98
+ break;
99
+
100
+ case "lower-greek":
101
+ $text = unichr($n + 944);
102
+ break;
103
+ }
104
+
105
+ if ( $uppercase ) {
106
+ $text = strtoupper($text);
107
+ }
108
+
109
+ return "$text.";
110
+ }
111
+
112
+ function render(Frame $frame) {
113
+ $style = $frame->get_style();
114
+ $font_size = $style->get_font_size();
115
+ $line_height = $style->length_in_pt($style->line_height, $frame->get_containing_block("w"));
116
+
117
+ $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
118
+
119
+ // Handle list-style-image
120
+ // If list style image is requested but missing, fall back to predefined types
121
+ if ( $style->list_style_image !== "none" &&
122
+ !Image_Cache::is_broken($img = $frame->get_image_url())) {
123
+
124
+ list($x,$y) = $frame->get_position();
125
+
126
+ //For expected size and aspect, instead of box size, use image natural size scaled to DPI.
127
+ // Resample the bullet image to be consistent with 'auto' sized images
128
+ // See also Image_Frame_Reflower::get_min_max_width
129
+ // Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
130
+ //$w = $frame->get_width();
131
+ //$h = $frame->get_height();
132
+ list($width, $height) = dompdf_getimagesize($img);
133
+ $w = (((float)rtrim($width, "px")) * 72) / DOMPDF_DPI;
134
+ $h = (((float)rtrim($height, "px")) * 72) / DOMPDF_DPI;
135
+
136
+ $x -= $w;
137
+ $y -= ($line_height - $font_size)/2; //Reverse hinting of list_bullet_positioner
138
+
139
+ $this->_canvas->image( $img, $x, $y, $w, $h);
140
+
141
+ } else {
142
+
143
+ $bullet_style = $style->list_style_type;
144
+
145
+ $fill = false;
146
+
147
+ switch ($bullet_style) {
148
+
149
+ default:
150
+ case "disc":
151
+ $fill = true;
152
+
153
+ case "circle":
154
+ list($x,$y) = $frame->get_position();
155
+ $r = ($font_size*(List_Bullet_Frame_Decorator::BULLET_SIZE /*-List_Bullet_Frame_Decorator::BULLET_THICKNESS*/ ))/2;
156
+ $x -= $font_size*(List_Bullet_Frame_Decorator::BULLET_SIZE/2);
157
+ $y += ($font_size*(1-List_Bullet_Frame_Decorator::BULLET_DESCENT))/2;
158
+ $o = $font_size*List_Bullet_Frame_Decorator::BULLET_THICKNESS;
159
+ $this->_canvas->circle($x, $y, $r, $style->color, $o, null, $fill);
160
+ break;
161
+
162
+ case "square":
163
+ list($x, $y) = $frame->get_position();
164
+ $w = $font_size*List_Bullet_Frame_Decorator::BULLET_SIZE;
165
+ $x -= $w;
166
+ $y += ($font_size*(1-List_Bullet_Frame_Decorator::BULLET_DESCENT-List_Bullet_Frame_Decorator::BULLET_SIZE))/2;
167
+ $this->_canvas->filled_rectangle($x, $y, $w, $w, $style->color);
168
+ break;
169
+
170
+ case "decimal-leading-zero":
171
+ case "decimal":
172
+ case "lower-alpha":
173
+ case "lower-latin":
174
+ case "lower-roman":
175
+ case "lower-greek":
176
+ case "upper-alpha":
177
+ case "upper-latin":
178
+ case "upper-roman":
179
+ case "1": // HTML 4.0 compatibility
180
+ case "a":
181
+ case "i":
182
+ case "A":
183
+ case "I":
184
+ $li = $frame->get_parent();
185
+
186
+ $pad = null;
187
+ if ( $bullet_style === "decimal-leading-zero" ) {
188
+ $pad = strlen($li->get_parent()->get_node()->getAttribute("dompdf-children-count"));
189
+ }
190
+
191
+ $index = $frame->get_node()->getAttribute("dompdf-counter");
192
+ $text = $this->make_counter($index, $bullet_style, $pad);
193
+
194
+ if ( trim($text) == "" ) {
195
+ return;
196
+ }
197
+
198
+ $spacing = 0;
199
+ $font_family = $style->font_family;
200
+
201
+ $line = $li->get_containing_line();
202
+ list($x, $y) = array($frame->get_position("x"), $line->y);
203
+
204
+ $x -= Font_Metrics::get_text_width($text, $font_family, $font_size, $spacing);
205
+
206
+ // Take line-height into account
207
+ $line_height = $style->line_height;
208
+ $y += ($line_height - $font_size) / 4; // FIXME I thought it should be 2, but 4 gives better results
209
+
210
+ $this->_canvas->text($x, $y, $text,
211
+ $font_family, $font_size,
212
+ $style->color, $spacing);
213
+
214
+ case "none":
215
+ break;
216
+ }
217
+ }
218
+ }
219
+ }
dompdf/include/null_frame_decorator.cls.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: null_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Dummy decorator
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Null_Frame_Decorator extends Frame_Decorator {
17
+
18
+ function __construct(Frame $frame, DOMPDF $dompdf) {
19
+ parent::__construct($frame, $dompdf);
20
+ $style = $this->_frame->get_style();
21
+ $style->width = 0;
22
+ $style->height = 0;
23
+ $style->margin = 0;
24
+ $style->padding = 0;
25
+ }
26
+
27
+ }
dompdf/include/null_frame_reflower.cls.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: null_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Dummy reflower
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Null_Frame_Reflower extends Frame_Reflower {
17
+
18
+ function __construct(Frame $frame) { parent::__construct($frame); }
19
+
20
+ function reflow(Frame_Decorator $block = null) { return; }
21
+
22
+ }
dompdf/include/null_positioner.cls.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: null_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Dummy positioner
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Null_Positioner extends Positioner {
17
+
18
+ function __construct(Frame_Decorator $frame) {
19
+ parent::__construct($frame);
20
+ }
21
+
22
+ function position() { return; }
23
+
24
+ }
dompdf/include/page_cache.cls.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: page_cache.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Caches individual rendered PDF pages
12
+ *
13
+ * Not totally implemented yet. Use at your own risk ;)
14
+ *
15
+ * @access private
16
+ * @package dompdf
17
+ * @static
18
+ */
19
+ class Page_Cache {
20
+
21
+ const DB_USER = "dompdf_page_cache";
22
+ const DB_PASS = "some meaningful password";
23
+ const DB_NAME = "dompdf_page_cache";
24
+
25
+ static private $__connection = null;
26
+
27
+ function init() {
28
+ if ( is_null(self::$__connection) ) {
29
+ $con_str = "host=" . DB_HOST .
30
+ " dbname=" . self::DB_NAME .
31
+ " user=" . self::DB_USER .
32
+ " password=" . self::DB_PASS;
33
+
34
+ if ( !self::$__connection = pg_connect($con_str) )
35
+ throw new Exception("Database connection failed.");
36
+ }
37
+ }
38
+
39
+ function __construct() { throw new Exception("Can not create instance of Page_Class. Class is static."); }
40
+
41
+ private static function __query($sql) {
42
+ if ( !($res = pg_query(self::$__connection, $sql)) )
43
+ throw new Exception(pg_last_error(self::$__connection));
44
+ return $res;
45
+ }
46
+
47
+ static function store_page($id, $page_num, $data) {
48
+ $where = "WHERE id='" . pg_escape_string($id) . "' AND ".
49
+ "page_num=". pg_escape_string($page_num);
50
+
51
+ $res = self::__query("SELECT timestamp FROM page_cache ". $where);
52
+
53
+ $row = pg_fetch_assoc($res);
54
+
55
+ if ( $row )
56
+ self::__query("UPDATE page_cache SET data='" . pg_escape_string($data) . "' " . $where);
57
+ else
58
+ self::__query("INSERT INTO page_cache (id, page_num, data) VALUES ('" . pg_escape_string($id) . "', ".
59
+ pg_escape_string($page_num) . ", ".
60
+ "'". pg_escape_string($data) . "')");
61
+
62
+ }
63
+
64
+ static function store_fonts($id, $fonts) {
65
+ self::__query("BEGIN");
66
+ // Update the font information
67
+ self::__query("DELETE FROM page_fonts WHERE id='" . pg_escape_string($id) . "'");
68
+
69
+ foreach (array_keys($fonts) as $font)
70
+ self::__query("INSERT INTO page_fonts (id, font_name) VALUES ('" .
71
+ pg_escape_string($id) . "', '" . pg_escape_string($font) . "')");
72
+ self::__query("COMMIT");
73
+ }
74
+
75
+ // static function retrieve_page($id, $page_num) {
76
+
77
+ // $res = self::__query("SELECT data FROM page_cache WHERE id='" . pg_escape_string($id) . "' AND ".
78
+ // "page_num=". pg_escape_string($page_num));
79
+
80
+ // $row = pg_fetch_assoc($res);
81
+
82
+ // return pg_unescape_bytea($row["data"]);
83
+
84
+ // }
85
+
86
+ static function get_page_timestamp($id, $page_num) {
87
+ $res = self::__query("SELECT timestamp FROM page_cache WHERE id='" . pg_escape_string($id) . "' AND ".
88
+ "page_num=". pg_escape_string($page_num));
89
+
90
+ $row = pg_fetch_assoc($res);
91
+
92
+ return $row["timestamp"];
93
+
94
+ }
95
+
96
+ // Adds the cached document referenced by $id to the provided pdf
97
+ static function insert_cached_document(CPDF_Adapter $pdf, $id, $new_page = true) {
98
+ $res = self::__query("SELECT font_name FROM page_fonts WHERE id='" . pg_escape_string($id) . "'");
99
+
100
+ // Ensure that the fonts needed by the cached document are loaded into
101
+ // the pdf
102
+ while ($row = pg_fetch_assoc($res))
103
+ $pdf->get_cpdf()->selectFont($row["font_name"]);
104
+
105
+ $res = self::__query("SELECT data FROM page_cache WHERE id='" . pg_escape_string($id) . "'");
106
+
107
+ if ( $new_page )
108
+ $pdf->new_page();
109
+
110
+ $first = true;
111
+ while ($row = pg_fetch_assoc($res)) {
112
+
113
+ if ( !$first )
114
+ $pdf->new_page();
115
+ else
116
+ $first = false;
117
+
118
+ $page = $pdf->reopen_serialized_object($row["data"]);
119
+ //$pdf->close_object();
120
+ $pdf->add_object($page, "add");
121
+
122
+ }
123
+
124
+ }
125
+ }
126
+
127
+ Page_Cache::init();
dompdf/include/page_frame_decorator.cls.php ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: page_frame_decorator.cls.php 457 2012-01-22 11:48:20Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Decorates frames for page layout
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Page_Frame_Decorator extends Frame_Decorator {
17
+
18
+ /**
19
+ * y value of bottom page margin
20
+ *
21
+ * @var float
22
+ */
23
+ protected $_bottom_page_margin;
24
+
25
+ /**
26
+ * Flag indicating page is full.
27
+ *
28
+ * @var bool
29
+ */
30
+ protected $_page_full;
31
+
32
+ /**
33
+ * Number of tables currently being reflowed
34
+ *
35
+ * @var int
36
+ */
37
+ protected $_in_table;
38
+
39
+ /**
40
+ * The pdf renderer
41
+ *
42
+ * @var Renderer
43
+ */
44
+ protected $_renderer;
45
+
46
+ /**
47
+ * This page's floating frames
48
+ *
49
+ * @var array
50
+ */
51
+ protected $_floating_frames = array();
52
+
53
+ //........................................................................
54
+
55
+ /**
56
+ * Class constructor
57
+ *
58
+ * @param Frame $frame the frame to decorate
59
+ */
60
+ function __construct(Frame $frame, DOMPDF $dompdf) {
61
+ parent::__construct($frame, $dompdf);
62
+ $this->_page_full = false;
63
+ $this->_in_table = 0;
64
+ $this->_bottom_page_margin = null;
65
+ }
66
+
67
+ /**
68
+ * Set the renderer used for this pdf
69
+ *
70
+ * @param Renderer $renderer the renderer to use
71
+ */
72
+ function set_renderer($renderer) {
73
+ $this->_renderer = $renderer;
74
+ }
75
+
76
+ /**
77
+ * Return the renderer used for this pdf
78
+ *
79
+ * @return Renderer
80
+ */
81
+ function get_renderer() {
82
+ return $this->_renderer;
83
+ }
84
+
85
+ /**
86
+ * Set the frame's containing block. Overridden to set $this->_bottom_page_margin.
87
+ *
88
+ * @param float $x
89
+ * @param float $y
90
+ * @param float $w
91
+ * @param float $h
92
+ */
93
+ function set_containing_block($x = null, $y = null, $w = null, $h = null) {
94
+ parent::set_containing_block($x,$y,$w,$h);
95
+ //$w = $this->get_containing_block("w");
96
+ if ( isset($h) )
97
+ $this->_bottom_page_margin = $h; // - $this->_frame->get_style()->length_in_pt($this->_frame->get_style()->margin_bottom, $w);
98
+ }
99
+
100
+ /**
101
+ * Returns true if the page is full and is no longer accepting frames.
102
+ *
103
+ * @return bool
104
+ */
105
+ function is_full() {
106
+ return $this->_page_full;
107
+ }
108
+
109
+ /**
110
+ * Start a new page by resetting the full flag.
111
+ */
112
+ function next_page() {
113
+ $this->_floating_frames = array();
114
+ $this->_renderer->new_page();
115
+ $this->_page_full = false;
116
+ }
117
+
118
+ /**
119
+ * Indicate to the page that a table is currently being reflowed.
120
+ */
121
+ function table_reflow_start() {
122
+ $this->_in_table++;
123
+ }
124
+
125
+ /**
126
+ * Indicate to the page that table reflow is finished.
127
+ */
128
+ function table_reflow_end() {
129
+ $this->_in_table--;
130
+ }
131
+
132
+ /**
133
+ * Return whether we are currently in a nested table or not
134
+ *
135
+ * @return bool
136
+ */
137
+ function in_nested_table() {
138
+ return $this->_in_table > 1;
139
+ }
140
+
141
+ /**
142
+ * Check if a forced page break is required before $frame. This uses the
143
+ * frame's page_break_before property as well as the preceeding frame's
144
+ * page_break_after property.
145
+ *
146
+ * @link http://www.w3.org/TR/CSS21/page.html#forced
147
+ *
148
+ * @param Frame $frame the frame to check
149
+ * @return bool true if a page break occured
150
+ */
151
+ function check_forced_page_break(Frame $frame) {
152
+
153
+ // Skip check if page is already split
154
+ if ( $this->_page_full )
155
+ return;
156
+
157
+ $block_types = array("block", "list-item", "table", "inline");
158
+ $page_breaks = array("always", "left", "right");
159
+
160
+ $style = $frame->get_style();
161
+
162
+ if ( !in_array($style->display, $block_types) )
163
+ return false;
164
+
165
+ // Find the previous block-level sibling
166
+ $prev = $frame->get_prev_sibling();
167
+
168
+ while ( $prev && !in_array($prev->get_style()->display, $block_types) )
169
+ $prev = $prev->get_prev_sibling();
170
+
171
+
172
+ if ( in_array($style->page_break_before, $page_breaks) ) {
173
+
174
+ // Prevent cascading splits
175
+ $frame->split(null, true);
176
+ // We have to grab the style again here because split() resets
177
+ // $frame->style to the frame's orignal style.
178
+ $frame->get_style()->page_break_before = "auto";
179
+ $this->_page_full = true;
180
+
181
+ return true;
182
+ }
183
+
184
+ if ( $prev && in_array($prev->get_style()->page_break_after, $page_breaks) ) {
185
+ // Prevent cascading splits
186
+ $frame->split(null, true);
187
+ $prev->get_style()->page_break_after = "auto";
188
+ $this->_page_full = true;
189
+ return true;
190
+ }
191
+
192
+ if( $prev && $prev->get_last_child() && $frame->get_node()->nodeName != "body" ) {
193
+ $prev_last_child = $prev->get_last_child();
194
+ if ( in_array($prev_last_child->get_style()->page_break_after, $page_breaks) ) {
195
+ $frame->split(null, true);
196
+ $prev_last_child->get_style()->page_break_after = "auto";
197
+ $this->_page_full = true;
198
+ return true;
199
+ }
200
+ }
201
+
202
+
203
+ return false;
204
+ }
205
+
206
+ /**
207
+ * Determine if a page break is allowed before $frame
208
+ * http://www.w3.org/TR/CSS21/page.html#allowed-page-breaks
209
+ *
210
+ * In the normal flow, page breaks can occur at the following places:
211
+ *
212
+ * 1. In the vertical margin between block boxes. When a page
213
+ * break occurs here, the used values of the relevant
214
+ * 'margin-top' and 'margin-bottom' properties are set to '0'.
215
+ * 2. Between line boxes inside a block box.
216
+ *
217
+ * These breaks are subject to the following rules:
218
+ *
219
+ * * Rule A: Breaking at (1) is allowed only if the
220
+ * 'page-break-after' and 'page-break-before' properties of
221
+ * all the elements generating boxes that meet at this margin
222
+ * allow it, which is when at least one of them has the value
223
+ * 'always', 'left', or 'right', or when all of them are
224
+ * 'auto'.
225
+ *
226
+ * * Rule B: However, if all of them are 'auto' and the
227
+ * nearest common ancestor of all the elements has a
228
+ * 'page-break-inside' value of 'avoid', then breaking here is
229
+ * not allowed.
230
+ *
231
+ * * Rule C: Breaking at (2) is allowed only if the number of
232
+ * line boxes between the break and the start of the enclosing
233
+ * block box is the value of 'orphans' or more, and the number
234
+ * of line boxes between the break and the end of the box is
235
+ * the value of 'widows' or more.
236
+ *
237
+ * * Rule D: In addition, breaking at (2) is allowed only if
238
+ * the 'page-break-inside' property is 'auto'.
239
+ *
240
+ * If the above doesn't provide enough break points to keep
241
+ * content from overflowing the page boxes, then rules B and D are
242
+ * dropped in order to find additional breakpoints.
243
+ *
244
+ * If that still does not lead to sufficient break points, rules A
245
+ * and C are dropped as well, to find still more break points.
246
+ *
247
+ * We will also allow breaks between table rows. However, when
248
+ * splitting a table, the table headers should carry over to the
249
+ * next page (but they don't yet).
250
+ *
251
+ * @param Frame $frame the frame to check
252
+ * @return bool true if a break is allowed, false otherwise
253
+ */
254
+ protected function _page_break_allowed(Frame $frame) {
255
+
256
+ $block_types = array("block", "list-item", "table", "-dompdf-image");
257
+ dompdf_debug("page-break", "_page_break_allowed(" . $frame->get_node()->nodeName. ")");
258
+ $display = $frame->get_style()->display;
259
+
260
+ // Block Frames (1):
261
+ if ( in_array($display, $block_types) ) {
262
+
263
+ // Avoid breaks within table-cells
264
+ if ( $this->_in_table ) {
265
+ dompdf_debug("page-break", "In table: " . $this->_in_table);
266
+ return false;
267
+ }
268
+
269
+ // Rules A & B
270
+
271
+ if ( $frame->get_style()->page_break_before === "avoid" ) {
272
+ dompdf_debug("page-break", "before: avoid");
273
+ return false;
274
+ }
275
+
276
+ // Find the preceeding block-level sibling
277
+ $prev = $frame->get_prev_sibling();
278
+ while ( $prev && !in_array($prev->get_style()->display, $block_types) )
279
+ $prev = $prev->get_prev_sibling();
280
+
281
+ // Does the previous element allow a page break after?
282
+ if ( $prev && $prev->get_style()->page_break_after === "avoid" ) {
283
+ dompdf_debug("page-break", "after: avoid");
284
+ return false;
285
+ }
286
+
287
+ // If both $prev & $frame have the same parent, check the parent's
288
+ // page_break_inside property.
289
+ $parent = $frame->get_parent();
290
+ if ( $prev && $parent && $parent->get_style()->page_break_inside === "avoid" ) {
291
+ dompdf_debug("page-break", "parent inside: avoid");
292
+ return false;
293
+ }
294
+
295
+ // To prevent cascading page breaks when a top-level element has
296
+ // page-break-inside: avoid, ensure that at least one frame is
297
+ // on the page before splitting.
298
+ if ( $parent->get_node()->nodeName === "body" && !$prev ) {
299
+ // We are the body's first child
300
+ dompdf_debug("page-break", "Body's first child.");
301
+ return false;
302
+ }
303
+
304
+ // If the frame is the first block-level frame, use the value from
305
+ // $frame's parent instead.
306
+ if ( !$prev && $parent )
307
+ return $this->_page_break_allowed( $parent );
308
+
309
+ dompdf_debug("page-break", "block: break allowed");
310
+ return true;
311
+
312
+ }
313
+
314
+ // Inline frames (2):
315
+ else if ( in_array($display, Style::$INLINE_TYPES) ) {
316
+
317
+ // Avoid breaks within table-cells
318
+ if ( $this->_in_table ) {
319
+ dompdf_debug("page-break", "In table: " . $this->_in_table);
320
+ return false;
321
+ }
322
+
323
+ // Rule C
324
+ $block_parent = $frame->find_block_parent();
325
+ if ( count($block_parent->get_line_boxes() ) < $frame->get_style()->orphans ) {
326
+ dompdf_debug("page-break", "orphans");
327
+ return false;
328
+ }
329
+
330
+ // FIXME: Checking widows is tricky without having laid out the
331
+ // remaining line boxes. Just ignore it for now...
332
+
333
+ // Rule D
334
+ $p = $block_parent;
335
+ while ($p) {
336
+ if ( $p->get_style()->page_break_inside === "avoid" ) {
337
+ dompdf_debug("page-break", "parent->inside: avoid");
338
+ return false;
339
+ }
340
+ $p = $p->find_block_parent();
341
+ }
342
+
343
+ // To prevent cascading page breaks when a top-level element has
344
+ // page-break-inside: avoid, ensure that at least one frame with
345
+ // some content is on the page before splitting.
346
+ $prev = $frame->get_prev_sibling();
347
+ while ( $prev && ($prev->is_text_node() && trim($prev->get_node()->nodeValue) == "") )
348
+ $prev = $prev->get_prev_sibling();
349
+
350
+ if ( $block_parent->get_node()->nodeName === "body" && !$prev ) {
351
+ // We are the body's first child
352
+ dompdf_debug("page-break", "Body's first child.");
353
+ return false;
354
+ }
355
+
356
+ // Skip breaks on empty text nodes
357
+ if ( $frame->is_text_node() &&
358
+ $frame->get_node()->nodeValue == "" )
359
+ return false;
360
+
361
+ dompdf_debug("page-break", "inline: break allowed");
362
+ return true;
363
+
364
+ // Table-rows
365
+ } else if ( $display === "table-row" ) {
366
+
367
+ // Simply check if the parent table's page_break_inside property is
368
+ // not 'avoid'
369
+ $p = Table_Frame_Decorator::find_parent_table($frame);
370
+
371
+ while ($p) {
372
+ if ( $p->get_style()->page_break_inside === "avoid" ) {
373
+ dompdf_debug("page-break", "parent->inside: avoid");
374
+ return false;
375
+ }
376
+ $p = $p->find_block_parent();
377
+ }
378
+
379
+ // Avoid breaking after the first row of a table
380
+ if ( $p && $p->get_first_child() === $frame) {
381
+ dompdf_debug("page-break", "table: first-row");
382
+ return false;
383
+ }
384
+
385
+ // If this is a nested table, prevent the page from breaking
386
+ if ( $this->_in_table > 1 ) {
387
+ dompdf_debug("page-break", "table: nested table");
388
+ return false;
389
+ }
390
+
391
+ dompdf_debug("page-break","table-row/row-groups: break allowed");
392
+ return true;
393
+
394
+ } else if ( in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) {
395
+
396
+ // Disallow breaks at row-groups: only split at row boundaries
397
+ return false;
398
+
399
+ } else {
400
+
401
+ dompdf_debug("page-break", "? " . $frame->get_style()->display . "");
402
+ return false;
403
+ }
404
+
405
+ }
406
+
407
+ /**
408
+ * Check if $frame will fit on the page. If the frame does not fit,
409
+ * the frame tree is modified so that a page break occurs in the
410
+ * correct location.
411
+ *
412
+ * @param Frame $frame the frame to check
413
+ * @return Frame the frame following the page break
414
+ */
415
+ function check_page_break(Frame $frame) {
416
+ // Do not split if we have already or if the frame was already
417
+ // pushed to the next page (prevents infinite loops)
418
+ if ( $this->_page_full || $frame->_already_pushed ) {
419
+ return false;
420
+ }
421
+
422
+ // If the frame is absolute of fixed it shouldn't break
423
+ $p = $frame;
424
+ do {
425
+ if ( $p->is_absolute() )
426
+ return false;
427
+ } while ( $p = $p->get_parent() );
428
+
429
+ $margin_height = $frame->get_margin_height();
430
+
431
+ // FIXME If the row is taller than the page and
432
+ // if it the first of the page, we don't break
433
+ if ( $frame->get_style()->display === "table-row" &&
434
+ !$frame->get_prev_sibling() &&
435
+ $margin_height > $this->get_margin_height() )
436
+ return false;
437
+
438
+ // Determine the frame's maximum y value
439
+ $max_y = $frame->get_position("y") + $margin_height;
440
+
441
+ // If a split is to occur here, then the bottom margins & paddings of all
442
+ // parents of $frame must fit on the page as well:
443
+ $p = $frame->get_parent();
444
+ while ( $p ) {
445
+ $style = $p->get_style();
446
+ $max_y += $style->length_in_pt(array($style->margin_bottom,
447
+ $style->padding_bottom,
448
+ $style->border_bottom_width));
449
+ $p = $p->get_parent();
450
+ }
451
+
452
+
453
+ // Check if $frame flows off the page
454
+ if ( $max_y <= $this->_bottom_page_margin )
455
+ // no: do nothing
456
+ return false;
457
+
458
+ dompdf_debug("page-break", "check_page_break");
459
+ dompdf_debug("page-break", "in_table: " . $this->_in_table);
460
+
461
+ // yes: determine page break location
462
+ $iter = $frame;
463
+ $flg = false;
464
+
465
+ $in_table = $this->_in_table;
466
+
467
+ dompdf_debug("page-break","Starting search");
468
+ while ( $iter ) {
469
+ // echo "\nbacktrack: " .$iter->get_node()->nodeName ." ".spl_object_hash($iter->get_node()). "";
470
+ if ( $iter === $this ) {
471
+ dompdf_debug("page-break", "reached root.");
472
+ // We've reached the root in our search. Just split at $frame.
473
+ break;
474
+ }
475
+
476
+ if ( $this->_page_break_allowed($iter) ) {
477
+ dompdf_debug("page-break","break allowed, splitting.");
478
+ $iter->split(null, true);
479
+ $this->_page_full = true;
480
+ $this->_in_table = $in_table;
481
+ $frame->_already_pushed = true;
482
+ return true;
483
+ }
484
+
485
+ if ( !$flg && $next = $iter->get_last_child() ) {
486
+ dompdf_debug("page-break", "following last child.");
487
+
488
+ if ( $next->is_table() )
489
+ $this->_in_table++;
490
+
491
+ $iter = $next;
492
+ continue;
493
+ }
494
+
495
+ if ( $next = $iter->get_prev_sibling() ) {
496
+ dompdf_debug("page-break", "following prev sibling.");
497
+
498
+ if ( $next->is_table() && !$iter->is_table() )
499
+ $this->_in_table++;
500
+
501
+ else if ( !$next->is_table() && $iter->is_table() )
502
+ $this->_in_table--;
503
+
504
+ $iter = $next;
505
+ $flg = false;
506
+ continue;
507
+ }
508
+
509
+ if ( $next = $iter->get_parent() ) {
510
+ dompdf_debug("page-break", "following parent.");
511
+
512
+ if ( $iter->is_table() )
513
+ $this->_in_table--;
514
+
515
+ $iter = $next;
516
+ $flg = true;
517
+ continue;
518
+ }
519
+
520
+ break;
521
+ }
522
+
523
+ $this->_in_table = $in_table;
524
+
525
+ // No valid page break found. Just break at $frame.
526
+ dompdf_debug("page-break", "no valid break found, just splitting.");
527
+
528
+ // If we are in a table, backtrack to the nearest top-level table row
529
+ if ( $this->_in_table ) {
530
+ $num_tables = $this->_in_table - 1;
531
+
532
+ $iter = $frame;
533
+ while ( $iter && $num_tables && $iter->get_style()->display !== "table" ) {
534
+ $iter = $iter->get_parent();
535
+ $num_tables--;
536
+ }
537
+
538
+ $iter = $frame;
539
+ while ($iter && $iter->get_style()->display !== "table-row" )
540
+ $iter = $iter->get_parent();
541
+ }
542
+
543
+ $frame->split(null, true);
544
+ $this->_page_full = true;
545
+ $frame->_already_pushed = true;
546
+ return true;
547
+
548
+ }
549
+
550
+ //........................................................................
551
+
552
+ function split($frame = null, $force_pagebreak = false) {
553
+ // Do nothing
554
+ }
555
+
556
+ /**
557
+ * Add a floating frame
558
+ *
559
+ * @param $child Frame
560
+ */
561
+ function add_floating_frame(Frame $frame) {
562
+ array_unshift($this->_floating_frames, $frame);
563
+ }
564
+
565
+ /**
566
+ * @return array
567
+ */
568
+ function get_floating_frames() {
569
+ return $this->_floating_frames;
570
+ }
571
+
572
+ public function remove_floating_frame($key) {
573
+ unset($this->_floating_frames[$key]);
574
+ }
575
+
576
+ public function get_lowest_float_offset(Frame $child) {
577
+ $style = $child->get_style();
578
+ $side = $style->clear;
579
+ $float = $style->float;
580
+
581
+ $y = 0;
582
+
583
+ foreach($this->_floating_frames as $key => $frame) {
584
+ if ( $side === "both" || $frame->get_style()->float === $side ) {
585
+ $y = max($y, $frame->get_position("y") + $frame->get_margin_height());
586
+
587
+ if ( $float !== "none" ) {
588
+ $this->remove_floating_frame($key);
589
+ }
590
+ }
591
+ }
592
+
593
+ return $y;
594
+ }
595
+
596
+ }
dompdf/include/page_frame_reflower.cls.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: page_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Reflows pages
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Page_Frame_Reflower extends Frame_Reflower {
18
+
19
+ /**
20
+ * Cache of the callbacks array
21
+ *
22
+ * @var array
23
+ */
24
+ private $_callbacks;
25
+
26
+ /**
27
+ * Cache of the canvas
28
+ *
29
+ * @var Canvas
30
+ */
31
+ private $_canvas;
32
+
33
+ /**
34
+ * The stacking context, containing all z-indexed frames
35
+ * @var array
36
+ */
37
+ private $_stacking_context = array();
38
+
39
+ function __construct(Page_Frame_Decorator $frame) { parent::__construct($frame); }
40
+
41
+ /**
42
+ * @param $frame Frame
43
+ * @return void
44
+ */
45
+ function add_frame_to_stacking_context(Frame $frame, $z_index) {
46
+ $this->_stacking_context[$z_index][] = $frame;
47
+ }
48
+
49
+ function apply_page_style(Frame $frame, $page_number){
50
+ $style = $frame->get_style();
51
+ $page_styles = $style->get_stylesheet()->get_page_styles();
52
+
53
+ // http://www.w3.org/TR/CSS21/page.html#page-selectors
54
+ if ( count($page_styles) > 1 ) {
55
+ $odd = $page_number % 2 == 1;
56
+ $first = $page_number == 1;
57
+
58
+ $style = clone $page_styles["base"];
59
+
60
+ // FIXME RTL
61
+ if ( $odd && isset($page_styles[":right"]) ) {
62
+ $style->merge($page_styles[":right"]);
63
+ }
64
+
65
+ if ( $odd && isset($page_styles[":odd"]) ) {
66
+ $style->merge($page_styles[":odd"]);
67
+ }
68
+
69
+ // FIXME RTL
70
+ if ( !$odd && isset($page_styles[":left"]) ) {
71
+ $style->merge($page_styles[":left"]);
72
+ }
73
+
74
+ if ( !$odd && isset($page_styles[":even"]) ) {
75
+ $style->merge($page_styles[":even"]);
76
+ }
77
+
78
+ if ( $first && isset($page_styles[":first"]) ) {
79
+ $style->merge($page_styles[":first"]);
80
+ }
81
+
82
+ $frame->set_style($style);
83
+ }
84
+ }
85
+
86
+ //........................................................................
87
+
88
+ /**
89
+ * Paged layout:
90
+ * http://www.w3.org/TR/CSS21/page.html
91
+ */
92
+ function reflow(Frame_Decorator $block = null) {
93
+ $fixed_children = array();
94
+ $prev_child = null;
95
+ $child = $this->_frame->get_first_child();
96
+ $current_page = 0;
97
+
98
+ while ($child) {
99
+ $this->apply_page_style($this->_frame, $current_page + 1);
100
+
101
+ $style = $this->_frame->get_style();
102
+
103
+ // Pages are only concerned with margins
104
+ $cb = $this->_frame->get_containing_block();
105
+ $left = $style->length_in_pt($style->margin_left, $cb["w"]);
106
+ $right = $style->length_in_pt($style->margin_right, $cb["w"]);
107
+ $top = $style->length_in_pt($style->margin_top, $cb["h"]);
108
+ $bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]);
109
+
110
+ $content_x = $cb["x"] + $left;
111
+ $content_y = $cb["y"] + $top;
112
+ $content_width = $cb["w"] - $left - $right;
113
+ $content_height = $cb["h"] - $top - $bottom;
114
+
115
+ // Only if it's the first page, we save the nodes with a fixed position
116
+ if ($current_page == 0) {
117
+ $children = $child->get_children();
118
+ foreach ($children as $onechild) {
119
+ if ($onechild->get_style()->position === "fixed") {
120
+ $fixed_children[] = $onechild->deep_copy();
121
+ }
122
+ }
123
+ $fixed_children = array_reverse($fixed_children);
124
+ }
125
+
126
+ $child->set_containing_block($content_x, $content_y, $content_width, $content_height);
127
+
128
+ // Check for begin reflow callback
129
+ $this->_check_callbacks("begin_page_reflow", $child);
130
+
131
+ //Insert a copy of each node which have a fixed position
132
+ if ($current_page >= 1) {
133
+ foreach ($fixed_children as $fixed_child) {
134
+ $child->insert_child_before($fixed_child->deep_copy(), $child->get_first_child());
135
+ }
136
+ }
137
+
138
+ $child->reflow();
139
+ $next_child = $child->get_next_sibling();
140
+
141
+ // Check for begin render callback
142
+ $this->_check_callbacks("begin_page_render", $child);
143
+
144
+ $renderer = $this->_frame->get_renderer();
145
+
146
+ // Render the page
147
+ $renderer->render($child);
148
+
149
+ Renderer::$stacking_first_pass = false;
150
+
151
+ // http://www.w3.org/TR/CSS21/visuren.html#z-index
152
+ ksort($this->_stacking_context);
153
+
154
+ foreach( $this->_stacking_context as $_frames ) {
155
+ foreach ( $_frames as $_frame ) {
156
+ $renderer->render($_frame);
157
+ }
158
+ }
159
+
160
+ Renderer::$stacking_first_pass = true;
161
+ $this->_stacking_context = array();
162
+
163
+ // Check for end render callback
164
+ $this->_check_callbacks("end_page_render", $child);
165
+
166
+ if ( $next_child ) {
167
+ $this->_frame->next_page();
168
+ }
169
+
170
+ // Wait to dispose of all frames on the previous page
171
+ // so callback will have access to them
172
+ if ( $prev_child ) {
173
+ $prev_child->dispose(true);
174
+ }
175
+ $prev_child = $child;
176
+ $child = $next_child;
177
+ $current_page++;
178
+ }
179
+
180
+ // Dispose of previous page if it still exists
181
+ if ( $prev_child ) {
182
+ $prev_child->dispose(true);
183
+ }
184
+ }
185
+
186
+ //........................................................................
187
+
188
+ /**
189
+ * Check for callbacks that need to be performed when a given event
190
+ * gets triggered on a page
191
+ *
192
+ * @param string $event the type of event
193
+ * @param Frame $frame the frame that event is triggered on
194
+ */
195
+ protected function _check_callbacks($event, $frame) {
196
+ if (!isset($this->_callbacks)) {
197
+ $dompdf = $this->_frame->get_dompdf();
198
+ $this->_callbacks = $dompdf->get_callbacks();
199
+ $this->_canvas = $dompdf->get_canvas();
200
+ }
201
+
202
+ if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) {
203
+ $info = array(0 => $this->_canvas, "canvas" => $this->_canvas,
204
+ 1 => $frame, "frame" => $frame);
205
+ $fs = $this->_callbacks[$event];
206
+ foreach ($fs as $f) {
207
+ if (is_callable($f)) {
208
+ if (is_array($f)) {
209
+ $f[0]->$f[1]($info);
210
+ } else {
211
+ $f($info);
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
dompdf/include/pdflib_adapter.cls.php ADDED
@@ -0,0 +1,1030 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: pdflib_adapter.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * PDF rendering interface
13
+ *
14
+ * PDFLib_Adapter provides a simple, stateless interface to the one
15
+ * provided by PDFLib.
16
+ *
17
+ * Unless otherwise mentioned, all dimensions are in points (1/72 in).
18
+ * The coordinate origin is in the top left corner and y values
19
+ * increase downwards.
20
+ *
21
+ * See {@link http://www.pdflib.com/} for more complete documentation
22
+ * on the underlying PDFlib functions.
23
+ *
24
+ * @package dompdf
25
+ */
26
+ class PDFLib_Adapter implements Canvas {
27
+
28
+ /**
29
+ * Dimensions of paper sizes in points
30
+ *
31
+ * @var array;
32
+ */
33
+ static public $PAPER_SIZES = array(); // Set to
34
+ // CPDF_Adapter::$PAPER_SIZES below.
35
+
36
+ /**
37
+ * Whether to create PDFs in memory or on disk
38
+ *
39
+ * @var bool
40
+ */
41
+ static $IN_MEMORY = true;
42
+
43
+ /**
44
+ * Instance of PDFLib class
45
+ *
46
+ * @var PDFlib
47
+ */
48
+ private $_pdf;
49
+
50
+ /**
51
+ * Name of temporary file used for PDFs created on disk
52
+ *
53
+ * @var string
54
+ */
55
+ private $_file;
56
+
57
+ /**
58
+ * PDF width, in points
59
+ *
60
+ * @var float
61
+ */
62
+ private $_width;
63
+
64
+ /**
65
+ * PDF height, in points
66
+ *
67
+ * @var height
68
+ */
69
+ private $_height;
70
+
71
+ /**
72
+ * Last fill colour used
73
+ *
74
+ * @var array
75
+ */
76
+ private $_last_fill_color;
77
+
78
+ /**
79
+ * Last stroke colour used
80
+ *
81
+ * @var array
82
+ */
83
+ private $_last_stroke_color;
84
+
85
+ /**
86
+ * Cache of image handles
87
+ *
88
+ * @var array
89
+ */
90
+ private $_imgs;
91
+
92
+ /**
93
+ * Cache of font handles
94
+ *
95
+ * @var array
96
+ */
97
+ private $_fonts;
98
+
99
+ /**
100
+ * List of objects (templates) to add to multiple pages
101
+ *
102
+ * @var array
103
+ */
104
+ private $_objs;
105
+
106
+ /**
107
+ * Current page number
108
+ *
109
+ * @var int
110
+ */
111
+ private $_page_number;
112
+
113
+ /**
114
+ * Total number of pages
115
+ *
116
+ * @var int
117
+ */
118
+ private $_page_count;
119
+
120
+ /**
121
+ * Text to display on every page
122
+ *
123
+ * @var array
124
+ */
125
+ private $_page_text;
126
+
127
+ /**
128
+ * Array of pages for accesing after rendering is initially complete
129
+ *
130
+ * @var array
131
+ */
132
+ private $_pages;
133
+
134
+ /**
135
+ * Class constructor
136
+ *
137
+ * @param mixed $paper The size of paper to use either a string (see {@link CPDF_Adapter::$PAPER_SIZES}) or
138
+ * an array(xmin,ymin,xmax,ymax)
139
+ * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
140
+ */
141
+ function __construct($paper = "letter", $orientation = "portrait") {
142
+ if ( is_array($paper) )
143
+ $size = $paper;
144
+ else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) )
145
+ $size = self::$PAPER_SIZES[mb_strtolower($paper)];
146
+ else
147
+ $size = self::$PAPER_SIZES["letter"];
148
+
149
+ if ( mb_strtolower($orientation) === "landscape" ) {
150
+ list($size[2], $size[3]) = array($size[3], $size[2]);
151
+ }
152
+
153
+ $this->_width = $size[2] - $size[0];
154
+ $this->_height= $size[3] - $size[1];
155
+
156
+ $this->_pdf = new PDFLib();
157
+
158
+ if ( defined("DOMPDF_PDFLIB_LICENSE") )
159
+ $this->_pdf->set_parameter( "license", DOMPDF_PDFLIB_LICENSE);
160
+
161
+ $this->_pdf->set_parameter("textformat", "utf8");
162
+ $this->_pdf->set_parameter("fontwarning", "false");
163
+
164
+ $this->_pdf->set_info("Creator", "DOMPDF");
165
+
166
+ // Silence pedantic warnings about missing TZ settings
167
+ $tz = @date_default_timezone_get();
168
+ date_default_timezone_set("UTC");
169
+ $this->_pdf->set_info("Date", date("Y-m-d"));
170
+ date_default_timezone_set($tz);
171
+
172
+ if ( self::$IN_MEMORY )
173
+ $this->_pdf->begin_document("","");
174
+ else {
175
+ $tempname = tempnam(DOMPDF_TEMP_DIR, "libdompdf_pdf_");
176
+ @unlink($tempname);
177
+ $this->_file = "$tempname.pdf";
178
+ $this->_pdf->begin_document($this->_file,"");
179
+ }
180
+
181
+ $this->_pdf->begin_page_ext($this->_width, $this->_height, "");
182
+
183
+ $this->_page_number = $this->_page_count = 1;
184
+ $this->_page_text = array();
185
+
186
+ $this->_imgs = array();
187
+ $this->_fonts = array();
188
+ $this->_objs = array();
189
+
190
+ // Set up font paths
191
+ $families = Font_Metrics::get_font_families();
192
+ foreach ($families as $family => $files) {
193
+ foreach ($files as $style => $file) {
194
+ $face = basename($file);
195
+
196
+ // Prefer ttfs to afms
197
+ if ( file_exists("$file.ttf") ) {
198
+ $outline = "$file.ttf";
199
+ $afm = null;
200
+
201
+ } else if ( file_exists("$file.TTF") ) {
202
+ $outline = "$file.TTF";
203
+ $afm = null;
204
+
205
+ } else if ( file_exists("$file.pfb") ) {
206
+ $outline = "$file.pfb";
207
+
208
+ if ( file_exists("$file.afm") )
209
+ $afm = "$file.afm";
210
+
211
+ } else if ( file_exists("$file.PFB") ) {
212
+ $outline = "$file.PFB";
213
+ if ( file_exists("$file.AFM") )
214
+ $afm = "$file.AFM";
215
+ } else
216
+ continue;
217
+
218
+ $this->_pdf->set_parameter("FontOutline", "\{$face\}=\{$outline\}");
219
+ if ( !is_null($afm) )
220
+ $this->_pdf->set_parameter("FontAFM", "\{$face\}=\{$afm\}");
221
+ }
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Close the pdf
227
+ */
228
+ protected function _close() {
229
+ $this->_place_objects();
230
+
231
+ // Close all pages
232
+ $this->_pdf->suspend_page("");
233
+ for ($p = 1; $p <= $this->_page_count; $p++) {
234
+ $this->_pdf->resume_page("pagenumber=$p");
235
+ $this->_pdf->end_page_ext("");
236
+ }
237
+
238
+ $this->_pdf->end_document("");
239
+ }
240
+
241
+
242
+ /**
243
+ * Returns the PDFLib instance
244
+ *
245
+ * @return PDFLib
246
+ */
247
+ function get_pdflib() { return $this->_pdf; }
248
+
249
+ /**
250
+ * Add meta information to the PDF
251
+ *
252
+ * @param string $label label of the value (Creator, Producter, etc.)
253
+ * @param string $value the text to set
254
+ */
255
+ function add_info($label, $value) {
256
+ $this->_pdf->set_info($label, $value);
257
+ }
258
+
259
+ /**
260
+ * Opens a new 'object' (template in PDFLib-speak)
261
+ *
262
+ * While an object is open, all drawing actions are recorded to the
263
+ * object instead of being drawn on the current page. Objects can
264
+ * be added later to a specific page or to several pages.
265
+ *
266
+ * The return value is an integer ID for the new object.
267
+ *
268
+ * @see PDFLib_Adapter::close_object()
269
+ * @see PDFLib_Adapter::add_object()
270
+ *
271
+ * @return int
272
+ */
273
+ function open_object() {
274
+ $this->_pdf->suspend_page("");
275
+ $ret = $this->_pdf->begin_template($this->_width, $this->_height);
276
+ $this->_pdf->save();
277
+ $this->_objs[$ret] = array("start_page" => $this->_page_number);
278
+ return $ret;
279
+ }
280
+
281
+ /**
282
+ * Reopen an existing object (NOT IMPLEMENTED)
283
+ *
284
+ * PDFLib does not seem to support reopening templates.
285
+ *
286
+ * @param int $object the ID of a previously opened object
287
+ */
288
+ function reopen_object($object) {
289
+ throw new DOMPDF_Exception("PDFLib does not support reopening objects.");
290
+ }
291
+
292
+ /**
293
+ * Close the current template
294
+ *
295
+ * @see PDFLib_Adapter::open_object()
296
+ */
297
+ function close_object() {
298
+ $this->_pdf->restore();
299
+ $this->_pdf->end_template();
300
+ $this->_pdf->resume_page("pagenumber=".$this->_page_number);
301
+ }
302
+
303
+ /**
304
+ * Adds the specified object to the document
305
+ *
306
+ * $where can be one of:
307
+ * - 'add' add to current page only
308
+ * - 'all' add to every page from the current one onwards
309
+ * - 'odd' add to all odd numbered pages from now on
310
+ * - 'even' add to all even numbered pages from now on
311
+ * - 'next' add the object to the next page only
312
+ * - 'nextodd' add to all odd numbered pages from the next one
313
+ * - 'nexteven' add to all even numbered pages from the next one
314
+ *
315
+ * @param int $object the object handle returned by open_object()
316
+ * @param string $where
317
+ */
318
+ function add_object($object, $where = 'all') {
319
+
320
+ if ( mb_strpos($where, "next") !== false ) {
321
+ $this->_objs[$object]["start_page"]++;
322
+ $where = str_replace("next", "", $where);
323
+ if ( $where == "" )
324
+ $where = "add";
325
+ }
326
+
327
+ $this->_objs[$object]["where"] = $where;
328
+ }
329
+
330
+ /**
331
+ * Stops the specified template from appearing in the document.
332
+ *
333
+ * The object will stop being displayed on the page following the
334
+ * current one.
335
+ *
336
+ * @param int $object
337
+ */
338
+ function stop_object($object) {
339
+
340
+ if ( !isset($this->_objs[$object]) )
341
+ return;
342
+
343
+ $start = $this->_objs[$object]["start_page"];
344
+ $where = $this->_objs[$object]["where"];
345
+
346
+ // Place the object on this page if required
347
+ if ( $this->_page_number >= $start &&
348
+ (($this->_page_number % 2 == 0 && $where === "even") ||
349
+ ($this->_page_number % 2 == 1 && $where === "odd") ||
350
+ ($where === "all")) )
351
+ $this->_pdf->fit_image($object,0,0,"");
352
+
353
+ $this->_objs[$object] = null;
354
+ unset($this->_objs[$object]);
355
+ }
356
+
357
+ /**
358
+ * Add all active objects to the current page
359
+ */
360
+ protected function _place_objects() {
361
+
362
+ foreach ( $this->_objs as $obj => $props ) {
363
+ $start = $props["start_page"];
364
+ $where = $props["where"];
365
+
366
+ // Place the object on this page if required
367
+ if ( $this->_page_number >= $start &&
368
+ (($this->_page_number % 2 == 0 && $where === "even") ||
369
+ ($this->_page_number % 2 == 1 && $where === "odd") ||
370
+ ($where === "all")) ) {
371
+ $this->_pdf->fit_image($obj,0,0,"");
372
+ }
373
+ }
374
+
375
+ }
376
+
377
+ function get_width() { return $this->_width; }
378
+
379
+ function get_height() { return $this->_height; }
380
+
381
+ function get_page_number() { return $this->_page_number; }
382
+
383
+ function get_page_count() { return $this->_page_count; }
384
+
385
+ function set_page_number($num) { $this->_page_number = (int)$num; }
386
+
387
+ function set_page_count($count) { $this->_page_count = (int)$count; }
388
+
389
+
390
+ /**
391
+ * Sets the line style
392
+ *
393
+ * @param float width
394
+ * @param string corner
395
+ * @param string join
396
+ * @param array dash
397
+ */
398
+ protected function _set_line_style($width, $cap, $join, $dash) {
399
+
400
+ if ( count($dash) == 1 )
401
+ $dash[] = $dash[0];
402
+
403
+ if ( count($dash) > 1 )
404
+ $this->_pdf->setdashpattern("dasharray={" . implode(" ", $dash) . "}");
405
+ else
406
+ $this->_pdf->setdash(0,0);
407
+
408
+ switch ( $join ) {
409
+ case "miter":
410
+ $this->_pdf->setlinejoin(0);
411
+ break;
412
+
413
+ case "round":
414
+ $this->_pdf->setlinejoin(1);
415
+ break;
416
+
417
+ case "bevel":
418
+ $this->_pdf->setlinejoin(2);
419
+ break;
420
+
421
+ default:
422
+ break;
423
+ }
424
+
425
+ switch ( $cap ) {
426
+ case "butt":
427
+ $this->_pdf->setlinecap(0);
428
+ break;
429
+
430
+ case "round":
431
+ $this->_pdf->setlinecap(1);
432
+ break;
433
+
434
+ case "square":
435
+ $this->_pdf->setlinecap(2);
436
+ break;
437
+
438
+ default:
439
+ break;
440
+ }
441
+
442
+ $this->_pdf->setlinewidth($width);
443
+
444
+ }
445
+
446
+ /**
447
+ * Sets the line color
448
+ *
449
+ * @param array $color array(r,g,b)
450
+ */
451
+ protected function _set_stroke_color($color) {
452
+ if($this->_last_stroke_color == $color)
453
+ return;
454
+
455
+ $this->_last_stroke_color = $color;
456
+
457
+ if (isset($color[3])) {
458
+ $type = "cmyk";
459
+ list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], $color[3]);
460
+ }
461
+ elseif (isset($color[2])) {
462
+ $type = "rgb";
463
+ list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], null);
464
+ }
465
+ else {
466
+ $type = "gray";
467
+ list($c1, $c2, $c3, $c4) = array($color[0], $color[1], null, null);
468
+ }
469
+
470
+ $this->_pdf->setcolor("stroke", $type, $c1, $c2, $c3, $c4);
471
+ }
472
+
473
+ /**
474
+ * Sets the fill color
475
+ *
476
+ * @param array $color array(r,g,b)
477
+ */
478
+ protected function _set_fill_color($color) {
479
+ if($this->_last_fill_color == $color)
480
+ return;
481
+
482
+ $this->_last_fill_color = $color;
483
+
484
+ if (isset($color[3])) {
485
+ $type = "cmyk";
486
+ list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], $color[3]);
487
+ }
488
+ elseif (isset($color[2])) {
489
+ $type = "rgb";
490
+ list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], null);
491
+ }
492
+ else {
493
+ $type = "gray";
494
+ list($c1, $c2, $c3, $c4) = array($color[0], $color[1], null, null);
495
+ }
496
+
497
+ $this->_pdf->setcolor("fill", $type, $c1, $c2, $c3, $c4);
498
+ }
499
+
500
+ /**
501
+ * Sets the opacity
502
+ *
503
+ * @param $opacity
504
+ * @param $mode
505
+ */
506
+ function set_opacity($opacity, $mode = "Normal") {
507
+ if ( $mode === "Normal" ) {
508
+ $gstate = $this->_pdf->create_gstate("opacityfill=$opacity opacitystroke=$opacity");
509
+ $this->_pdf->set_gstate($gstate);
510
+ }
511
+ }
512
+
513
+ function set_default_view($view, $options = array()) {
514
+ // TODO
515
+ // http://www.pdflib.com/fileadmin/pdflib/pdf/manuals/PDFlib-8.0.2-API-reference.pdf
516
+ /**
517
+ * fitheight Fit the page height to the window, with the x coordinate left at the left edge of the window.
518
+ * fitrect Fit the rectangle specified by left, bottom, right, and top to the window.
519
+ * fitvisible Fit the visible contents of the page (the ArtBox) to the window.
520
+ * fitvisibleheight Fit the visible contents of the page to the window with the x coordinate left at the left edge of the window.
521
+ * fitvisiblewidth Fit the visible contents of the page to the window with the y coordinate top at the top edge of the window.
522
+ * fitwidth Fit the page width to the window, with the y coordinate top at the top edge of the window.
523
+ * fitwindow Fit the complete page to the window.
524
+ * fixed
525
+ */
526
+ //$this->_pdf->set_parameter("openaction", $view);
527
+ }
528
+
529
+ /**
530
+ * Loads a specific font and stores the corresponding descriptor.
531
+ *
532
+ * @param string $font
533
+ * @return int the font descriptor for the font
534
+ */
535
+ protected function _load_font($font, $encoding = null, $options = "") {
536
+
537
+ // Check if the font is a native PDF font
538
+ // Embed non-native fonts
539
+ $test = strtolower(basename($font));
540
+ if ( in_array($test, DOMPDF::$native_fonts) ) {
541
+ $font = basename($font);
542
+
543
+ } else {
544
+ // Embed non-native fonts
545
+ $options .= " embedding=true";
546
+ }
547
+
548
+ if ( is_null($encoding) ) {
549
+
550
+ // Unicode encoding is only available for the commerical
551
+ // version of PDFlib and not PDFlib-Lite
552
+ if ( defined("DOMPDF_PDFLIB_LICENSE") )
553
+ $encoding = "unicode";
554
+ else
555
+ $encoding = "auto";
556
+
557
+ }
558
+
559
+ $key = "$font:$encoding:$options";
560
+
561
+ if ( isset($this->_fonts[$key]) )
562
+ return $this->_fonts[$key];
563
+
564
+ else {
565
+
566
+ $this->_fonts[$key] = $this->_pdf->load_font($font, $encoding, $options);
567
+ return $this->_fonts[$key];
568
+
569
+ }
570
+
571
+ }
572
+
573
+ /**
574
+ * Remaps y coords from 4th to 1st quadrant
575
+ *
576
+ * @param float $y
577
+ * @return float
578
+ */
579
+ protected function y($y) { return $this->_height - $y; }
580
+
581
+ //........................................................................
582
+
583
+ function line($x1, $y1, $x2, $y2, $color, $width, $style = null) {
584
+ $this->_set_line_style($width, "butt", "", $style);
585
+ $this->_set_stroke_color($color);
586
+
587
+ $y1 = $this->y($y1);
588
+ $y2 = $this->y($y2);
589
+
590
+ $this->_pdf->moveto($x1,$y1);
591
+ $this->_pdf->lineto($x2, $y2);
592
+ $this->_pdf->stroke();
593
+ }
594
+
595
+ //........................................................................
596
+
597
+ function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) {
598
+ $this->_set_stroke_color($color);
599
+ $this->_set_line_style($width, "butt", "", $style);
600
+
601
+ $y1 = $this->y($y1) - $h;
602
+
603
+ $this->_pdf->rect($x1, $y1, $w, $h);
604
+ $this->_pdf->stroke();
605
+ }
606
+
607
+ //........................................................................
608
+
609
+ function filled_rectangle($x1, $y1, $w, $h, $color) {
610
+ $this->_set_fill_color($color);
611
+
612
+ $y1 = $this->y($y1) - $h;
613
+
614
+ $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h));
615
+ $this->_pdf->fill();
616
+ }
617
+
618
+ function clipping_rectangle($x1, $y1, $w, $h) {
619
+ $this->_pdf->save();
620
+
621
+ $y1 = $this->y($y1) - $h;
622
+
623
+ $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h));
624
+ $this->_pdf->clip();
625
+ }
626
+
627
+ function clipping_end() {
628
+ $this->_pdf->restore();
629
+ }
630
+
631
+ function save() {
632
+ $this->_pdf->save();
633
+ }
634
+
635
+ function restore() {
636
+ $this->_pdf->restore();
637
+ }
638
+
639
+ function rotate($angle, $x, $y) {
640
+ $pdf = $this->_pdf;
641
+ $pdf->translate($x, $this->_height-$y);
642
+ $pdf->rotate(-$angle);
643
+ $pdf->translate(-$x, -$this->_height+$y);
644
+ }
645
+
646
+ function skew($angle_x, $angle_y, $x, $y) {
647
+ $pdf = $this->_pdf;
648
+ $pdf->translate($x, $this->_height-$y);
649
+ $pdf->skew($angle_y, $angle_x); // Needs to be inverted
650
+ $pdf->translate(-$x, -$this->_height+$y);
651
+ }
652
+
653
+ function scale($s_x, $s_y, $x, $y) {
654
+ $pdf = $this->_pdf;
655
+ $pdf->translate($x, $this->_height-$y);
656
+ $pdf->scale($s_x, $s_y);
657
+ $pdf->translate(-$x, -$this->_height+$y);
658
+ }
659
+
660
+ function translate($t_x, $t_y) {
661
+ $this->_pdf->translate($t_x, -$t_y);
662
+ }
663
+
664
+ function transform($a, $b, $c, $d, $e, $f) {
665
+ $this->_pdf->concat($a, $b, $c, $d, $e, $f);
666
+ }
667
+
668
+ //........................................................................
669
+
670
+ function polygon($points, $color, $width = null, $style = null, $fill = false) {
671
+
672
+ $this->_set_fill_color($color);
673
+ $this->_set_stroke_color($color);
674
+
675
+ if ( !$fill && isset($width) )
676
+ $this->_set_line_style($width, "square", "miter", $style);
677
+
678
+ $y = $this->y(array_pop($points));
679
+ $x = array_pop($points);
680
+ $this->_pdf->moveto($x,$y);
681
+
682
+ while (count($points) > 1) {
683
+ $y = $this->y(array_pop($points));
684
+ $x = array_pop($points);
685
+ $this->_pdf->lineto($x,$y);
686
+ }
687
+
688
+ if ( $fill )
689
+ $this->_pdf->fill();
690
+ else
691
+ $this->_pdf->closepath_stroke();
692
+ }
693
+
694
+ //........................................................................
695
+
696
+ function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) {
697
+
698
+ $this->_set_fill_color($color);
699
+ $this->_set_stroke_color($color);
700
+
701
+ if ( !$fill && isset($width) )
702
+ $this->_set_line_style($width, "round", "round", $style);
703
+
704
+ $y = $this->y($y);
705
+
706
+ $this->_pdf->circle($x, $y, $r);
707
+
708
+ if ( $fill )
709
+ $this->_pdf->fill();
710
+ else
711
+ $this->_pdf->stroke();
712
+
713
+ }
714
+
715
+ //........................................................................
716
+
717
+ function image($img_url, $x, $y, $w, $h, $resolution = "normal") {
718
+ $w = (int)$w;
719
+ $h = (int)$h;
720
+
721
+ $img_type = Image_Cache::detect_type($img_url);
722
+ $img_ext = Image_Cache::type_to_ext($img_type);
723
+
724
+ if ( isset($this->_imgs[$img_url]) ) {
725
+ $img = $this->_imgs[$img_url];
726
+ }
727
+ else {
728
+ $img = $this->_imgs[$img_url] = $this->_pdf->load_image($img_type, $img_url, "");
729
+ }
730
+
731
+ $y = $this->y($y) - $h;
732
+ $this->_pdf->fit_image($img, $x, $y, "boxsize=\{$w $h\} fitmethod=entire");
733
+ }
734
+
735
+ //........................................................................
736
+
737
+ function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_spacing = 0, $char_spacing = 0, $angle = 0) {
738
+ $fh = $this->_load_font($font);
739
+
740
+ $this->_pdf->setfont($fh, $size);
741
+ $this->_set_fill_color($color);
742
+
743
+ $y = $this->y($y) - Font_Metrics::get_font_height($font, $size);
744
+
745
+ $word_spacing = (float)$word_spacing;
746
+ $char_spacing = (float)$char_spacing;
747
+ $angle = -(float)$angle;
748
+
749
+ $this->_pdf->fit_textline($text, $x, $y, "rotate=$angle wordspacing=$word_spacing charspacing=$char_spacing ");
750
+
751
+ }
752
+
753
+ //........................................................................
754
+
755
+ function javascript($code) {
756
+ if ( defined("DOMPDF_PDFLIB_LICENSE") ) {
757
+ $this->_pdf->create_action("JavaScript", $code);
758
+ }
759
+ }
760
+
761
+ //........................................................................
762
+
763
+ /**
764
+ * Add a named destination (similar to <a name="foo">...</a> in html)
765
+ *
766
+ * @param string $anchorname The name of the named destination
767
+ */
768
+ function add_named_dest($anchorname) {
769
+ $this->_pdf->add_nameddest($anchorname,"");
770
+ }
771
+
772
+ //........................................................................
773
+
774
+ /**
775
+ * Add a link to the pdf
776
+ *
777
+ * @param string $url The url to link to
778
+ * @param float $x The x position of the link
779
+ * @param float $y The y position of the link
780
+ * @param float $width The width of the link
781
+ * @param float $height The height of the link
782
+ */
783
+ function add_link($url, $x, $y, $width, $height) {
784
+
785
+ $y = $this->y($y) - $height;
786
+ if ( strpos($url, '#') === 0 ) {
787
+ // Local link
788
+ $name = substr($url,1);
789
+ if ( $name )
790
+ $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={$url} destname=". substr($url,1) . " linewidth=0");
791
+ } else {
792
+
793
+ list($proto, $host, $path, $file) = explode_url($url);
794
+
795
+ if ( $proto == "" || $proto === "file://" )
796
+ return; // Local links are not allowed
797
+ $url = build_url($proto, $host, $path, $file);
798
+ $url = '{' . rawurldecode($url) . '}';
799
+
800
+ $action = $this->_pdf->create_action("URI", "url=" . $url);
801
+ $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={$url} action={activate=$action} linewidth=0");
802
+ }
803
+ }
804
+
805
+ //........................................................................
806
+
807
+ function get_text_width($text, $font, $size, $word_spacing = 0, $letter_spacing = 0) {
808
+ $fh = $this->_load_font($font);
809
+
810
+ // Determine the additional width due to extra spacing
811
+ $num_spaces = mb_substr_count($text," ");
812
+ $delta = $word_spacing * $num_spaces;
813
+
814
+ if ( $letter_spacing ) {
815
+ $num_chars = mb_strlen($text);
816
+ $delta += ($num_chars - $num_spaces) * $letter_spacing;
817
+ }
818
+
819
+ return $this->_pdf->stringwidth($text, $fh, $size) + $delta;
820
+ }
821
+
822
+ //........................................................................
823
+
824
+ function get_font_height($font, $size) {
825
+
826
+ $fh = $this->_load_font($font);
827
+
828
+ $this->_pdf->setfont($fh, $size);
829
+
830
+ $asc = $this->_pdf->get_value("ascender", $fh);
831
+ $desc = $this->_pdf->get_value("descender", $fh);
832
+
833
+ // $desc is usually < 0,
834
+ return $size * ($asc - $desc) * DOMPDF_FONT_HEIGHT_RATIO;
835
+ }
836
+
837
+ function get_font_baseline($font, $size) {
838
+ return $this->get_font_height($font, $size) / DOMPDF_FONT_HEIGHT_RATIO * 1.1;
839
+ }
840
+
841
+ //........................................................................
842
+
843
+ /**
844
+ * Writes text at the specified x and y coordinates on every page
845
+ *
846
+ * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
847
+ * with their current values.
848
+ *
849
+ * See {@link Style::munge_colour()} for the format of the colour array.
850
+ *
851
+ * @param float $x
852
+ * @param float $y
853
+ * @param string $text the text to write
854
+ * @param string $font the font file to use
855
+ * @param float $size the font size, in points
856
+ * @param array $color
857
+ * @param float $adjust word spacing adjustment
858
+ * @param float $angle angle to write the text at, measured CW starting from the x-axis
859
+ */
860
+ function page_text($x, $y, $text, $font, $size, $color = array(0,0,0),
861
+ $adjust = 0, $angle = 0) {
862
+ $_t = "text";
863
+ $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "adjust", "angle");
864
+ }
865
+
866
+ //........................................................................
867
+
868
+ /**
869
+ * Processes a script on every page
870
+ *
871
+ * The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available.
872
+ *
873
+ * This function can be used to add page numbers to all pages
874
+ * after the first one, for example.
875
+ *
876
+ * @param string $code the script code
877
+ * @param string $type the language type for script
878
+ */
879
+ function page_script($code, $type = "text/php") {
880
+ $_t = "script";
881
+ $this->_page_text[] = compact("_t", "code", "type");
882
+ }
883
+
884
+ //........................................................................
885
+
886
+ function new_page() {
887
+
888
+ // Add objects to the current page
889
+ $this->_place_objects();
890
+
891
+ $this->_pdf->suspend_page("");
892
+ $this->_pdf->begin_page_ext($this->_width, $this->_height, "");
893
+ $this->_page_number = ++$this->_page_count;
894
+
895
+ }
896
+
897
+ //........................................................................
898
+
899
+ /**
900
+ * Add text to each page after rendering is complete
901
+ */
902
+ protected function _add_page_text() {
903
+
904
+ if ( !count($this->_page_text) )
905
+ return;
906
+
907
+ $this->_pdf->suspend_page("");
908
+
909
+ for ($p = 1; $p <= $this->_page_count; $p++) {
910
+ $this->_pdf->resume_page("pagenumber=$p");
911
+
912
+ foreach ($this->_page_text as $pt) {
913
+ extract($pt);
914
+
915
+ switch ($_t) {
916
+
917
+ case "text":
918
+ $text = str_replace(array("{PAGE_NUM}","{PAGE_COUNT}"),
919
+ array($p, $this->_page_count), $text);
920
+ $this->text($x, $y, $text, $font, $size, $color, $adjust, $angle);
921
+ break;
922
+
923
+ case "script":
924
+ if (!$eval) {
925
+ $eval = new PHP_Evaluator($this);
926
+ }
927
+ $eval->evaluate($code, array('PAGE_NUM' => $p, 'PAGE_COUNT' => $this->_page_count));
928
+ break;
929
+ }
930
+ }
931
+
932
+ $this->_pdf->suspend_page("");
933
+ }
934
+
935
+ $this->_pdf->resume_page("pagenumber=".$this->_page_number);
936
+ }
937
+
938
+ //........................................................................
939
+
940
+ function stream($filename, $options = null) {
941
+
942
+ // Add page text
943
+ $this->_add_page_text();
944
+
945
+ if ( isset($options["compress"]) && $options["compress"] != 1 )
946
+ $this->_pdf->set_value("compress", 0);
947
+ else
948
+ $this->_pdf->set_value("compress", 6);
949
+
950
+ $this->_close();
951
+
952
+ if ( self::$IN_MEMORY ) {
953
+ $data = $this->_pdf->get_buffer();
954
+ $size = strlen($data);
955
+
956
+ } else
957
+ $size = filesize($this->_file);
958
+
959
+
960
+ $filename = str_replace(array("\n","'"),"", $filename);
961
+ $attach = (isset($options["Attachment"]) && $options["Attachment"]) ? "attachment" : "inline";
962
+
963
+ header("Cache-Control: private");
964
+ header("Content-type: application/pdf");
965
+ header("Content-Disposition: $attach; filename=\"$filename\"");
966
+
967
+ //header("Content-length: " . $size);
968
+
969
+ if ( self::$IN_MEMORY )
970
+ echo $data;
971
+
972
+ else {
973
+
974
+ // Chunked readfile()
975
+ $chunk = (1 << 21); // 2 MB
976
+ $fh = fopen($this->_file, "rb");
977
+ if ( !$fh )
978
+ throw new DOMPDF_Exception("Unable to load temporary PDF file: " . $this->_file);
979
+
980
+ while ( !feof($fh) )
981
+ echo fread($fh,$chunk);
982
+ fclose($fh);
983
+
984
+ //debugpng
985
+ if (DEBUGPNG) print '[pdflib stream unlink '.$this->_file.']';
986
+ if (!DEBUGKEEPTEMP)
987
+
988
+ unlink($this->_file);
989
+ $this->_file = null;
990
+ unset($this->_file);
991
+ }
992
+
993
+ flush();
994
+ }
995
+
996
+ //........................................................................
997
+
998
+ function output($options = null) {
999
+
1000
+ // Add page text
1001
+ $this->_add_page_text();
1002
+
1003
+ if ( isset($options["compress"]) && $options["compress"] != 1 )
1004
+ $this->_pdf->set_value("compress", 0);
1005
+ else
1006
+ $this->_pdf->set_value("compress", 6);
1007
+
1008
+ $this->_close();
1009
+
1010
+ if ( self::$IN_MEMORY )
1011
+ $data = $this->_pdf->get_buffer();
1012
+
1013
+ else {
1014
+ $data = file_get_contents($this->_file);
1015
+
1016
+ //debugpng
1017
+ if (DEBUGPNG) print '[pdflib output unlink '.$this->_file.']';
1018
+ if (!DEBUGKEEPTEMP)
1019
+
1020
+ unlink($this->_file);
1021
+ $this->_file = null;
1022
+ unset($this->_file);
1023
+ }
1024
+
1025
+ return $data;
1026
+ }
1027
+ }
1028
+
1029
+ // Workaround for idiotic limitation on statics...
1030
+ PDFLib_Adapter::$PAPER_SIZES = CPDF_Adapter::$PAPER_SIZES;
dompdf/include/php_evaluator.cls.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: php_evaluator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Executes inline PHP code during the rendering process
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class PHP_Evaluator {
17
+
18
+ /**
19
+ * @var Canvas
20
+ */
21
+ protected $_canvas;
22
+
23
+ function __construct(Canvas $canvas) {
24
+ $this->_canvas = $canvas;
25
+ }
26
+
27
+ function evaluate($code, $vars = array()) {
28
+ if ( !DOMPDF_ENABLE_PHP )
29
+ return;
30
+
31
+ // Set up some variables for the inline code
32
+ $pdf = $this->_canvas;
33
+ $PAGE_NUM = $pdf->get_page_number();
34
+ $PAGE_COUNT = $pdf->get_page_count();
35
+
36
+ // Override those variables if passed in
37
+ foreach ($vars as $k => $v) {
38
+ $$k = $v;
39
+ }
40
+
41
+ //$code = html_entity_decode($code); // @todo uncomment this when tested
42
+ eval(utf8_decode($code));
43
+ }
44
+
45
+ function render($frame) {
46
+ $this->evaluate($frame->get_node()->nodeValue);
47
+ }
48
+ }
dompdf/include/positioner.cls.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Base Positioner class
12
+ *
13
+ * Defines postioner interface
14
+ *
15
+ * @access private
16
+ * @package dompdf
17
+ */
18
+ abstract class Positioner {
19
+
20
+ /**
21
+ * @var Frame_Decorator
22
+ */
23
+ protected $_frame;
24
+
25
+ //........................................................................
26
+
27
+ function __construct(Frame_Decorator $frame) {
28
+ $this->_frame = $frame;
29
+ }
30
+
31
+ /**
32
+ * Class destructor
33
+ */
34
+ function __destruct() {
35
+ clear_object($this);
36
+ }
37
+ //........................................................................
38
+
39
+ abstract function position();
40
+
41
+ function move($offset_x, $offset_y, $ignore_self = false) {
42
+ list($x, $y) = $this->_frame->get_position();
43
+
44
+ if ( !$ignore_self ) {
45
+ $this->_frame->set_position($x + $offset_x, $y + $offset_y);
46
+ }
47
+
48
+ foreach($this->_frame->get_children() as $child) {
49
+ $child->move($offset_x, $offset_y);
50
+ }
51
+ }
52
+ }
dompdf/include/renderer.cls.php ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: renderer.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Concrete renderer
12
+ *
13
+ * Instantiates several specific renderers in order to render any given
14
+ * frame.
15
+ *
16
+ * @access private
17
+ * @package dompdf
18
+ */
19
+ class Renderer extends Abstract_Renderer {
20
+
21
+ /**
22
+ * Array of renderers for specific frame types
23
+ *
24
+ * @var array
25
+ */
26
+ protected $_renderers;
27
+
28
+ /**
29
+ * Cache of the callbacks array
30
+ *
31
+ * @var array
32
+ */
33
+ private $_callbacks;
34
+
35
+ /**
36
+ * true when a stacking context is currently built
37
+ * @var bool
38
+ */
39
+ public static $stacking_first_pass = true;
40
+
41
+ /**
42
+ * Class destructor
43
+ */
44
+ function __destruct() {
45
+ clear_object($this);
46
+ }
47
+
48
+ /**
49
+ * Advance the canvas to the next page
50
+ */
51
+ function new_page() {
52
+ $this->_canvas->new_page();
53
+ }
54
+
55
+ /**
56
+ * Render frames recursively
57
+ *
58
+ * @param Frame $frame the frame to render
59
+ */
60
+ function render(Frame $frame, $stacking = false) {
61
+ global $_dompdf_debug;
62
+
63
+ if ( $_dompdf_debug ) {
64
+ echo $frame;
65
+ flush();
66
+ }
67
+
68
+ $style = $frame->get_style();
69
+
70
+ if ( in_array($style->visibility, array("hidden", "collapse")) ) {
71
+ return;
72
+ }
73
+
74
+ $render_self = self::$stacking_first_pass && !$stacking || !self::$stacking_first_pass;
75
+
76
+ if ( $render_self ) {
77
+ $display = $style->display;
78
+
79
+ // Starts the CSS transformation
80
+ if ( $style->transform && is_array($style->transform) ) {
81
+ $this->_canvas->save();
82
+ list($x, $y, $w, $h) = $frame->get_padding_box();
83
+ $origin = $style->transform_origin;
84
+
85
+ foreach($style->transform as $transform) {
86
+ list($function, $values) = $transform;
87
+ if ( $function === "matrix" ) {
88
+ $function = "transform";
89
+ }
90
+
91
+ $values = array_map("floatval", $values);
92
+ $values[] = $x + $style->length_in_pt($origin[0], $style->width);
93
+ $values[] = $y + $style->length_in_pt($origin[1], $style->height);
94
+
95
+ call_user_func_array(array($this->_canvas, $function), $values);
96
+ }
97
+ }
98
+
99
+ switch ($display) {
100
+
101
+ case "block":
102
+ case "list-item":
103
+ case "inline-block":
104
+ case "table":
105
+ case "inline-table":
106
+ $this->_render_frame("block", $frame);
107
+ break;
108
+
109
+ case "inline":
110
+ if ( $frame->is_text_node() )
111
+ $this->_render_frame("text", $frame);
112
+ else
113
+ $this->_render_frame("inline", $frame);
114
+ break;
115
+
116
+ case "table-cell":
117
+ $this->_render_frame("table-cell", $frame);
118
+ break;
119
+
120
+ case "table-row-group":
121
+ case "table-header-group":
122
+ case "table-footer-group":
123
+ $this->_render_frame("table-row-group", $frame);
124
+ break;
125
+
126
+ case "-dompdf-list-bullet":
127
+ $this->_render_frame("list-bullet", $frame);
128
+ break;
129
+
130
+ case "-dompdf-image":
131
+ $this->_render_frame("image", $frame);
132
+ break;
133
+
134
+ case "none":
135
+ $node = $frame->get_node();
136
+
137
+ if ( $node->nodeName === "script" ) {
138
+ if ( $node->getAttribute("type") === "text/php" ||
139
+ $node->getAttribute("language") === "php" ) {
140
+ // Evaluate embedded php scripts
141
+ $this->_render_frame("php", $frame);
142
+ }
143
+
144
+ elseif ( $node->getAttribute("type") === "text/javascript" ||
145
+ $node->getAttribute("language") === "javascript" ) {
146
+ // Insert JavaScript
147
+ $this->_render_frame("javascript", $frame);
148
+ }
149
+ }
150
+
151
+ // Don't render children, so skip to next iter
152
+ return;
153
+
154
+ default:
155
+ break;
156
+
157
+ }
158
+
159
+ // Check for begin frame callback
160
+ $this->_check_callbacks("begin_frame", $frame);
161
+
162
+ // Starts the overflow: hidden box
163
+ if ( $style->overflow === "hidden" ) {
164
+ list($x, $y, $w, $h) = $frame->get_padding_box();
165
+ $this->_canvas->clipping_rectangle($x, $y, $w, $h);
166
+ }
167
+ }
168
+
169
+ $page = $frame->get_root()->get_reflower();
170
+
171
+ foreach ($frame->get_children() as $child) {
172
+ $child_style = $child->get_style();
173
+ $_stacking = $stacking;
174
+
175
+ // Stacking context
176
+ if ( self::$stacking_first_pass && (
177
+ $child_style->z_index !== "auto" ||
178
+ $child_style->float !== "none" ||
179
+ $child->is_positionned()) ) {
180
+ $z_index = ($child_style->z_index === "auto") ? 0 : intval($child_style->z_index);
181
+ $page->add_frame_to_stacking_context($child, $z_index);
182
+ $_stacking = true;
183
+ }
184
+
185
+ $this->render($child, $_stacking);
186
+ }
187
+
188
+ if ( $render_self ) {
189
+ // Ends the overflow: hidden box
190
+ if ( $style->overflow === "hidden" ) {
191
+ $this->_canvas->clipping_end();
192
+ }
193
+
194
+ if ( $style->transform && is_array($style->transform) ) {
195
+ $this->_canvas->restore();
196
+ }
197
+
198
+ // Check for end frame callback
199
+ $this->_check_callbacks("end_frame", $frame);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Check for callbacks that need to be performed when a given event
205
+ * gets triggered on a frame
206
+ *
207
+ * @param string $event the type of event
208
+ * @param Frame $frame the frame that event is triggered on
209
+ */
210
+ protected function _check_callbacks($event, $frame) {
211
+ if (!isset($this->_callbacks)) {
212
+ $this->_callbacks = $this->_dompdf->get_callbacks();
213
+ }
214
+
215
+ if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) {
216
+ $info = array(0 => $this->_canvas, "canvas" => $this->_canvas,
217
+ 1 => $frame, "frame" => $frame);
218
+ $fs = $this->_callbacks[$event];
219
+ foreach ($fs as $f) {
220
+ if (is_callable($f)) {
221
+ if (is_array($f)) {
222
+ $f[0]->$f[1]($info);
223
+ } else {
224
+ $f($info);
225
+ }
226
+ }
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Render a single frame
233
+ *
234
+ * Creates Renderer objects on demand
235
+ *
236
+ * @param string $type type of renderer to use
237
+ * @param Frame $frame the frame to render
238
+ */
239
+ protected function _render_frame($type, $frame) {
240
+
241
+ if ( !isset($this->_renderers[$type]) ) {
242
+
243
+ switch ($type) {
244
+ case "block":
245
+ $this->_renderers[$type] = new Block_Renderer($this->_dompdf);
246
+ break;
247
+
248
+ case "inline":
249
+ $this->_renderers[$type] = new Inline_Renderer($this->_dompdf);
250
+ break;
251
+
252
+ case "text":
253
+ $this->_renderers[$type] = new Text_Renderer($this->_dompdf);
254
+ break;
255
+
256
+ case "image":
257
+ $this->_renderers[$type] = new Image_Renderer($this->_dompdf);
258
+ break;
259
+
260
+ case "table-cell":
261
+ $this->_renderers[$type] = new Table_Cell_Renderer($this->_dompdf);
262
+ break;
263
+
264
+ case "table-row-group":
265
+ $this->_renderers[$type] = new Table_Row_Group_Renderer($this->_dompdf);
266
+ break;
267
+
268
+ case "list-bullet":
269
+ $this->_renderers[$type] = new List_Bullet_Renderer($this->_dompdf);
270
+ break;
271
+
272
+ case "php":
273
+ $this->_renderers[$type] = new PHP_Evaluator($this->_canvas);
274
+ break;
275
+
276
+ case "javascript":
277
+ $this->_renderers[$type] = new Javascript_Embedder($this->_dompdf);
278
+ break;
279
+
280
+ }
281
+ }
282
+
283
+ $this->_renderers[$type]->render($frame);
284
+
285
+ }
286
+ }
dompdf/include/style.cls.php ADDED
@@ -0,0 +1,2211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: style.cls.php 469 2012-02-05 22:25:30Z fabien.menager $
10
+ */
11
+
12
+ /**
13
+ * Represents CSS properties.
14
+ *
15
+ * The Style class is responsible for handling and storing CSS properties.
16
+ * It includes methods to resolve colours and lengths, as well as getters &
17
+ * setters for many CSS properites.
18
+ *
19
+ * Actual CSS parsing is performed in the {@link Stylesheet} class.
20
+ *
21
+ * @package dompdf
22
+ */
23
+ class Style {
24
+
25
+ const CSS_IDENTIFIER = "-?[_a-zA-Z]+[_a-zA-Z0-9-]*";
26
+ const CSS_INTEGER = "-?\d+";
27
+
28
+ /**
29
+ * Default font size, in points.
30
+ *
31
+ * @var float
32
+ */
33
+ static $default_font_size = 12;
34
+
35
+ /**
36
+ * Default line height, as a fraction of the font size.
37
+ *
38
+ * @var float
39
+ */
40
+ static $default_line_height = 1.2;
41
+
42
+ /**
43
+ * Default "absolute" font sizes relative to the default font-size
44
+ * http://www.w3.org/TR/css3-fonts/#font-size-the-font-size-property
45
+ * @var array<float>
46
+ */
47
+ static $font_size_keywords = array(
48
+ "xx-small" => 0.6, // 3/5
49
+ "x-small" => 0.75, // 3/4
50
+ "small" => 0.889, // 8/9
51
+ "medium" => 1, // 1
52
+ "large" => 1.2, // 6/5
53
+ "x-large" => 1.5, // 3/2
54
+ "xx-large" => 2.0, // 2/1
55
+ );
56
+
57
+ /**
58
+ * List of all inline types. Should really be a constant.
59
+ *
60
+ * @var array
61
+ */
62
+ static $INLINE_TYPES = array("inline");
63
+
64
+ /**
65
+ * List of all block types. Should really be a constant.
66
+ *
67
+ * @var array
68
+ */
69
+ static $BLOCK_TYPES = array("block", "inline-block", "table-cell", "list-item");
70
+
71
+ /**
72
+ * List of all positionned types. Should really be a constant.
73
+ *
74
+ * @var array
75
+ */
76
+ static $POSITIONNED_TYPES = array("relative", "absolute", "fixed");
77
+
78
+ /**
79
+ * List of all table types. Should really be a constant.
80
+ *
81
+ * @var array;
82
+ */
83
+ static $TABLE_TYPES = array("table", "inline-table");
84
+
85
+ /**
86
+ * List of valid border styles. Should also really be a constant.
87
+ *
88
+ * @var array
89
+ */
90
+ static $BORDER_STYLES = array("none", "hidden", "dotted", "dashed", "solid",
91
+ "double", "groove", "ridge", "inset", "outset");
92
+
93
+ /**
94
+ * Default style values.
95
+ *
96
+ * @link http://www.w3.org/TR/CSS21/propidx.html
97
+ *
98
+ * @var array
99
+ */
100
+ static protected $_defaults = null;
101
+
102
+ /**
103
+ * List of inherited properties
104
+ *
105
+ * @link http://www.w3.org/TR/CSS21/propidx.html
106
+ *
107
+ * @var array
108
+ */
109
+ static protected $_inherited = null;
110
+
111
+ /**
112
+ * Caches method_exists result
113
+ *
114
+ * @var array<bool>
115
+ */
116
+ static protected $_methods_cache = array();
117
+
118
+ /**
119
+ * The stylesheet this style belongs to
120
+ *
121
+ * @see Stylesheet
122
+ * @var Stylesheet
123
+ */
124
+ protected $_stylesheet; // stylesheet this style is attached to
125
+
126
+ /**
127
+ * Main array of all CSS properties & values
128
+ *
129
+ * @var array
130
+ */
131
+ protected $_props;
132
+
133
+ /* var instead of protected would allow access outside of class */
134
+ protected $_important_props;
135
+
136
+ /**
137
+ * Cached property values
138
+ *
139
+ * @var array
140
+ */
141
+ protected $_prop_cache;
142
+
143
+ /**
144
+ * Font size of parent element in document tree. Used for relative font
145
+ * size resolution.
146
+ *
147
+ * @var float
148
+ */
149
+ protected $_parent_font_size; // Font size of parent element
150
+
151
+ /**
152
+ * @var Frame
153
+ */
154
+ protected $_frame;
155
+
156
+ /**
157
+ * The origin of the style
158
+ *
159
+ * @var int
160
+ */
161
+ protected $_origin = Stylesheet::ORIG_AUTHOR;
162
+
163
+ // private members
164
+ /**
165
+ * True once the font size is resolved absolutely
166
+ *
167
+ * @var bool
168
+ */
169
+ private $__font_size_calculated; // Cache flag
170
+
171
+ /**
172
+ * Class constructor
173
+ *
174
+ * @param Stylesheet $stylesheet the stylesheet this Style is associated with.
175
+ */
176
+ function __construct(Stylesheet $stylesheet, $origin = Stylesheet::ORIG_AUTHOR) {
177
+ $this->_props = array();
178
+ $this->_important_props = array();
179
+ $this->_stylesheet = $stylesheet;
180
+ $this->_origin = $origin;
181
+ $this->_parent_font_size = null;
182
+ $this->__font_size_calculated = false;
183
+
184
+ if ( !isset(self::$_defaults) ) {
185
+
186
+ // Shorthand
187
+ $d =& self::$_defaults;
188
+
189
+ // All CSS 2.1 properties, and their default values
190
+ $d["azimuth"] = "center";
191
+ $d["background_attachment"] = "scroll";
192
+ $d["background_color"] = "transparent";
193
+ $d["background_image"] = "none";
194
+ $d["background_image_resolution"] = "normal";
195
+ $d["_dompdf_background_image_resolution"] = $d["background_image_resolution"];
196
+ $d["background_position"] = "0% 0%";
197
+ $d["background_repeat"] = "repeat";
198
+ $d["background"] = "";
199
+ $d["border_collapse"] = "separate";
200
+ $d["border_color"] = "";
201
+ $d["border_spacing"] = "0";
202
+ $d["border_style"] = "";
203
+ $d["border_top"] = "";
204
+ $d["border_right"] = "";
205
+ $d["border_bottom"] = "";
206
+ $d["border_left"] = "";
207
+ $d["border_top_color"] = "";
208
+ $d["border_right_color"] = "";
209
+ $d["border_bottom_color"] = "";
210
+ $d["border_left_color"] = "";
211
+ $d["border_top_style"] = "none";
212
+ $d["border_right_style"] = "none";
213
+ $d["border_bottom_style"] = "none";
214
+ $d["border_left_style"] = "none";
215
+ $d["border_top_width"] = "medium";
216
+ $d["border_right_width"] = "medium";
217
+ $d["border_bottom_width"] = "medium";
218
+ $d["border_left_width"] = "medium";
219
+ $d["border_width"] = "medium";
220
+ $d["border"] = "";
221
+ $d["bottom"] = "auto";
222
+ $d["caption_side"] = "top";
223
+ $d["clear"] = "none";
224
+ $d["clip"] = "auto";
225
+ $d["color"] = "#000000";
226
+ $d["content"] = "normal";
227
+ $d["counter_increment"] = "none";
228
+ $d["counter_reset"] = "none";
229
+ $d["cue_after"] = "none";
230
+ $d["cue_before"] = "none";
231
+ $d["cue"] = "";
232
+ $d["cursor"] = "auto";
233
+ $d["direction"] = "ltr";
234
+ $d["display"] = "inline";
235
+ $d["elevation"] = "level";
236
+ $d["empty_cells"] = "show";
237
+ $d["float"] = "none";
238
+ $d["font_family"] = "serif";
239
+ $d["font_size"] = "medium";
240
+ $d["font_style"] = "normal";
241
+ $d["font_variant"] = "normal";
242
+ $d["font_weight"] = "normal";
243
+ $d["font"] = "";
244
+ $d["height"] = "auto";
245
+ $d["image_resolution"] = "normal";
246
+ $d["_dompdf_image_resolution"] = $d["image_resolution"];
247
+ $d["left"] = "auto";
248
+ $d["letter_spacing"] = "normal";
249
+ $d["line_height"] = "normal";
250
+ $d["list_style_image"] = "none";
251
+ $d["list_style_position"] = "outside";
252
+ $d["list_style_type"] = "disc";
253
+ $d["list_style"] = "";
254
+ $d["margin_right"] = "0";
255
+ $d["margin_left"] = "0";
256
+ $d["margin_top"] = "0";
257
+ $d["margin_bottom"] = "0";
258
+ $d["margin"] = "";
259
+ $d["max_height"] = "none";
260
+ $d["max_width"] = "none";
261
+ $d["min_height"] = "0";
262
+ $d["min_width"] = "0";
263
+ $d["opacity"] = "1.0"; // CSS3
264
+ $d["orphans"] = "2";
265
+ $d["outline_color"] = ""; // "invert" special color is not supported
266
+ $d["outline_style"] = "none";
267
+ $d["outline_width"] = "medium";
268
+ $d["outline"] = "";
269
+ $d["overflow"] = "visible";
270
+ $d["padding_top"] = "0";
271
+ $d["padding_right"] = "0";
272
+ $d["padding_bottom"] = "0";
273
+ $d["padding_left"] = "0";
274
+ $d["padding"] = "";
275
+ $d["page_break_after"] = "auto";
276
+ $d["page_break_before"] = "auto";
277
+ $d["page_break_inside"] = "auto";
278
+ $d["pause_after"] = "0";
279
+ $d["pause_before"] = "0";
280
+ $d["pause"] = "";
281
+ $d["pitch_range"] = "50";
282
+ $d["pitch"] = "medium";
283
+ $d["play_during"] = "auto";
284
+ $d["position"] = "static";
285
+ $d["quotes"] = "";
286
+ $d["richness"] = "50";
287
+ $d["right"] = "auto";
288
+ $d["size"] = "auto"; // @page
289
+ $d["speak_header"] = "once";
290
+ $d["speak_numeral"] = "continuous";
291
+ $d["speak_punctuation"] = "none";
292
+ $d["speak"] = "normal";
293
+ $d["speech_rate"] = "medium";
294
+ $d["stress"] = "50";
295
+ $d["table_layout"] = "auto";
296
+ $d["text_align"] = "left";
297
+ $d["text_decoration"] = "none";
298
+ $d["text_indent"] = "0";
299
+ $d["text_transform"] = "none";
300
+ $d["top"] = "auto";
301
+ $d["transform"] = "none"; // CSS3
302
+ $d["transform_origin"] = "50% 50%"; // CSS3
303
+ $d["_webkit_transform"] = $d["transform"]; // CSS3
304
+ $d["_webkit_transform_origin"] = $d["transform_origin"]; // CSS3
305
+ $d["unicode_bidi"] = "normal";
306
+ $d["vertical_align"] = "baseline";
307
+ $d["visibility"] = "visible";
308
+ $d["voice_family"] = "";
309
+ $d["volume"] = "medium";
310
+ $d["white_space"] = "normal";
311
+ $d["word_wrap"] = "normal";
312
+ $d["widows"] = "2";
313
+ $d["width"] = "auto";
314
+ $d["word_spacing"] = "normal";
315
+ $d["z_index"] = "auto";
316
+
317
+ // for @font-face
318
+ $d["src"] = "";
319
+ $d["unicode_range"] = "";
320
+
321
+ // Properties that inherit by default
322
+ self::$_inherited = array("azimuth",
323
+ "background_image_resolution",
324
+ "border_collapse",
325
+ "border_spacing",
326
+ "caption_side",
327
+ "color",
328
+ "cursor",
329
+ "direction",
330
+ "elevation",
331
+ "empty_cells",
332
+ "font_family",
333
+ "font_size",
334
+ "font_style",
335
+ "font_variant",
336
+ "font_weight",
337
+ "font",
338
+ "image_resolution",
339
+ "letter_spacing",
340
+ "line_height",
341
+ "list_style_image",
342
+ "list_style_position",
343
+ "list_style_type",
344
+ "list_style",
345
+ "orphans",
346
+ "page_break_inside",
347
+ "pitch_range",
348
+ "pitch",
349
+ "quotes",
350
+ "richness",
351
+ "speak_header",
352
+ "speak_numeral",
353
+ "speak_punctuation",
354
+ "speak",
355
+ "speech_rate",
356
+ "stress",
357
+ "text_align",
358
+ "text_indent",
359
+ "text_transform",
360
+ "visibility",
361
+ "voice_family",
362
+ "volume",
363
+ "white_space",
364
+ "word_wrap",
365
+ "widows",
366
+ "word_spacing");
367
+ }
368
+
369
+ }
370
+
371
+ /**
372
+ * "Destructor": forcibly free all references held by this object
373
+ */
374
+ function dispose() {
375
+ clear_object($this);
376
+ }
377
+
378
+ function set_frame(Frame $frame) {
379
+ $this->_frame = $frame;
380
+ }
381
+
382
+ function get_frame() {
383
+ return $this->_frame;
384
+ }
385
+
386
+ function set_origin($origin) {
387
+ $this->_origin = $origin;
388
+ }
389
+
390
+ function get_origin() {
391
+ return $this->_origin;
392
+ }
393
+
394
+ /**
395
+ * returns the {@link Stylesheet} this Style is associated with.
396
+ *
397
+ * @return Stylesheet
398
+ */
399
+ function get_stylesheet() { return $this->_stylesheet; }
400
+
401
+ /**
402
+ * Converts any CSS length value into an absolute length in points.
403
+ *
404
+ * length_in_pt() takes a single length (e.g. '1em') or an array of
405
+ * lengths and returns an absolute length. If an array is passed, then
406
+ * the return value is the sum of all elements.
407
+ *
408
+ * If a reference size is not provided, the default font size is used
409
+ * ({@link Style::$default_font_size}).
410
+ *
411
+ * @param float|array $length the length or array of lengths to resolve
412
+ * @param float $ref_size an absolute reference size to resolve percentage lengths
413
+ * @return float
414
+ */
415
+ function length_in_pt($length, $ref_size = null) {
416
+ static $cache = array();
417
+
418
+ if ( !is_array($length) )
419
+ $length = array($length);
420
+
421
+ if ( !isset($ref_size) )
422
+ $ref_size = self::$default_font_size;
423
+
424
+ $key = implode("@", $length)."/$ref_size";
425
+
426
+ if ( isset($cache[$key]) ) {
427
+ return $cache[$key];
428
+ }
429
+
430
+ $ret = 0;
431
+ foreach ($length as $l) {
432
+
433
+ if ( $l === "auto" )
434
+ return "auto";
435
+
436
+ if ( $l === "none" )
437
+ return "none";
438
+
439
+ // Assume numeric values are already in points
440
+ if ( is_numeric($l) ) {
441
+ $ret += $l;
442
+ continue;
443
+ }
444
+
445
+ if ( $l === "normal" ) {
446
+ $ret += $ref_size;
447
+ continue;
448
+ }
449
+
450
+ // Border lengths
451
+ if ( $l === "thin" ) {
452
+ $ret += 0.5;
453
+ continue;
454
+ }
455
+
456
+ if ( $l === "medium" ) {
457
+ $ret += 1.5;
458
+ continue;
459
+ }
460
+
461
+ if ( $l === "thick" ) {
462
+ $ret += 2.5;
463
+ continue;
464
+ }
465
+
466
+ if ( ($i = mb_strpos($l, "px")) !== false ) {
467
+ $ret += ( mb_substr($l, 0, $i) * 72 ) / DOMPDF_DPI;
468
+ continue;
469
+ }
470
+
471
+ if ( ($i = mb_strpos($l, "pt")) !== false ) {
472
+ $ret += mb_substr($l, 0, $i);
473
+ continue;
474
+ }
475
+
476
+ if ( ($i = mb_strpos($l, "%")) !== false ) {
477
+ $ret += mb_substr($l, 0, $i)/100 * $ref_size;
478
+ continue;
479
+ }
480
+
481
+ if ( ($i = mb_strpos($l, "rem")) !== false ) {
482
+ $ret += mb_substr($l, 0, $i) * $this->_stylesheet->get_dompdf()->get_tree()->get_root()->get_style()->font_size;
483
+ continue;
484
+ }
485
+
486
+ if ( ($i = mb_strpos($l, "em")) !== false ) {
487
+ $ret += mb_substr($l, 0, $i) * $this->__get("font_size");
488
+ continue;
489
+ }
490
+
491
+ if ( ($i = mb_strpos($l, "cm")) !== false ) {
492
+ $ret += mb_substr($l, 0, $i) * 72 / 2.54;
493
+ continue;
494
+ }
495
+
496
+ if ( ($i = mb_strpos($l, "mm")) !== false ) {
497
+ $ret += mb_substr($l, 0, $i) * 72 / 25.4;
498
+ continue;
499
+ }
500
+
501
+ // FIXME: em:ex ratio?
502
+ if ( ($i = mb_strpos($l, "ex")) !== false ) {
503
+ $ret += mb_substr($l, 0, $i) * $this->__get("font_size") / 2;
504
+ continue;
505
+ }
506
+
507
+ if ( ($i = mb_strpos($l, "in")) !== false ) {
508
+ $ret += mb_substr($l, 0, $i) * 72;
509
+ continue;
510
+ }
511
+
512
+ if ( ($i = mb_strpos($l, "pc")) !== false ) {
513
+ $ret += mb_substr($l, 0, $i) * 12;
514
+ continue;
515
+ }
516
+
517
+ // Bogus value
518
+ $ret += $ref_size;
519
+ }
520
+
521
+ return $cache[$key] = $ret;
522
+ }
523
+
524
+
525
+ /**
526
+ * Set inherited properties in this style using values in $parent
527
+ *
528
+ * @param Style $parent
529
+ */
530
+ function inherit(Style $parent) {
531
+
532
+ // Set parent font size
533
+ $this->_parent_font_size = $parent->get_font_size();
534
+
535
+ foreach (self::$_inherited as $prop) {
536
+ //inherit the !important property also.
537
+ //if local property is also !important, don't inherit.
538
+ if ( isset($parent->_props[$prop]) &&
539
+ ( !isset($this->_props[$prop]) ||
540
+ ( isset($parent->_important_props[$prop]) && !isset($this->_important_props[$prop]) )
541
+ )
542
+ ) {
543
+ if ( isset($parent->_important_props[$prop]) ) {
544
+ $this->_important_props[$prop] = true;
545
+ }
546
+ //see __set and __get, on all assignments clear cache!
547
+ $this->_prop_cache[$prop] = null;
548
+ $this->_props[$prop] = $parent->_props[$prop];
549
+ }
550
+ }
551
+
552
+ foreach (array_keys($this->_props) as $prop) {
553
+ if ( $this->_props[$prop] === "inherit" ) {
554
+ if ( isset($parent->_important_props[$prop]) ) {
555
+ $this->_important_props[$prop] = true;
556
+ }
557
+ //do not assign direct, but
558
+ //implicite assignment through __set, redirect to specialized, get value with __get
559
+ //This is for computing defaults if the parent setting is also missing.
560
+ //Therefore do not directly assign the value without __set
561
+ //set _important_props before that to be able to propagate.
562
+ //see __set and __get, on all assignments clear cache!
563
+ //$this->_prop_cache[$prop] = null;
564
+ //$this->_props[$prop] = $parent->_props[$prop];
565
+ //props_set for more obvious explicite assignment not implemented, because
566
+ //too many implicite uses.
567
+ // $this->props_set($prop, $parent->$prop);
568
+ $this->$prop = $parent->$prop;
569
+ }
570
+ }
571
+
572
+ return $this;
573
+ }
574
+
575
+ /**
576
+ * Override properties in this style with those in $style
577
+ *
578
+ * @param Style $style
579
+ */
580
+ function merge(Style $style) {
581
+ //treat the !important attribute
582
+ //if old rule has !important attribute, override with new rule only if
583
+ //the new rule is also !important
584
+ foreach($style->_props as $prop => $val ) {
585
+ if (isset($style->_important_props[$prop])) {
586
+ $this->_important_props[$prop] = true;
587
+ //see __set and __get, on all assignments clear cache!
588
+ $this->_prop_cache[$prop] = null;
589
+ $this->_props[$prop] = $val;
590
+ } else if ( !isset($this->_important_props[$prop]) ) {
591
+ //see __set and __get, on all assignments clear cache!
592
+ $this->_prop_cache[$prop] = null;
593
+ $this->_props[$prop] = $val;
594
+ }
595
+ }
596
+
597
+ if ( isset($style->_props["font_size"]) )
598
+ $this->__font_size_calculated = false;
599
+ }
600
+
601
+ /**
602
+ * Returns an array(r, g, b, "r"=> r, "g"=>g, "b"=>b, "hex"=>"#rrggbb")
603
+ * based on the provided CSS colour value.
604
+ *
605
+ * @param string $colour
606
+ * @return array
607
+ */
608
+ function munge_colour($colour) { return CSS_Color::parse($colour); }
609
+
610
+ /**
611
+ * Alias for {@link Style::munge_colour()}
612
+ *
613
+ * @param string $color
614
+ * @return array
615
+ */
616
+ function munge_color($color) { return CSS_Color::parse($color); }
617
+
618
+ /* direct access to _important_props array from outside would work only when declared as
619
+ * 'var $_important_props;' instead of 'protected $_important_props;'
620
+ * Don't call _set/__get on missing attribute. Therefore need a special access.
621
+ * Assume that __set will be also called when this is called, so do not check validity again.
622
+ * Only created, if !important exists -> always set true.
623
+ */
624
+ function important_set($prop) {
625
+ $prop = str_replace("-", "_", $prop);
626
+ $this->_important_props[$prop] = true;
627
+ }
628
+
629
+ function important_get($prop) {
630
+ isset($this->_important_props[$prop]);
631
+ }
632
+
633
+ /**
634
+ * PHP5 overloaded setter
635
+ *
636
+ * This function along with {@link Style::__get()} permit a user of the
637
+ * Style class to access any (CSS) property using the following syntax:
638
+ * <code>
639
+ * Style->margin_top = "1em";
640
+ * echo (Style->margin_top);
641
+ * </code>
642
+ *
643
+ * __set() automatically calls the provided set function, if one exists,
644
+ * otherwise it sets the property directly. Typically, __set() is not
645
+ * called directly from outside of this class.
646
+ *
647
+ * On each modification clear cache to return accurate setting.
648
+ * Also affects direct settings not using __set
649
+ * For easier finding all assignments, attempted to allowing only explicite assignment:
650
+ * Very many uses, e.g. frame_reflower.cls.php -> for now leave as it is
651
+ * function __set($prop, $val) {
652
+ * throw new DOMPDF_Exception("Implicite replacement of assignment by __set. Not good.");
653
+ * }
654
+ * function props_set($prop, $val) { ... }
655
+ *
656
+ * @param string $prop the property to set
657
+ * @param mixed $val the value of the property
658
+ *
659
+ */
660
+ function __set($prop, $val) {
661
+ $prop = str_replace("-", "_", $prop);
662
+ $this->_prop_cache[$prop] = null;
663
+
664
+ if ( !isset(self::$_defaults[$prop]) ) {
665
+ global $_dompdf_warnings;
666
+ $_dompdf_warnings[] = "'$prop' is not a valid CSS2 property.";
667
+ return;
668
+ }
669
+
670
+ if ( $prop !== "content" && is_string($val) && strlen($val) > 5 && mb_strpos($val, "url") === false ) {
671
+ $val = mb_strtolower(trim(str_replace(array("\n", "\t"), array(" "), $val)));
672
+ $val = preg_replace("/([0-9]+) (pt|px|pc|em|ex|in|cm|mm|%)/S", "\\1\\2", $val);
673
+ }
674
+
675
+ $method = "set_$prop";
676
+
677
+ if ( !isset(self::$_methods_cache[$method]) ) {
678
+ self::$_methods_cache[$method] = method_exists($this, $method);
679
+ }
680
+
681
+ if ( self::$_methods_cache[$method] )
682
+ $this->$method($val);
683
+ else
684
+ $this->_props[$prop] = $val;
685
+ }
686
+
687
+ /**
688
+ * PHP5 overloaded getter
689
+ *
690
+ * Along with {@link Style::__set()} __get() provides access to all CSS
691
+ * properties directly. Typically __get() is not called directly outside
692
+ * of this class.
693
+ *
694
+ * On each modification clear cache to return accurate setting.
695
+ * Also affects direct settings not using __set
696
+ *
697
+ * @param string $prop
698
+ * @return mixed
699
+ */
700
+ function __get($prop) {
701
+ if ( !isset(self::$_defaults[$prop]) )
702
+ throw new DOMPDF_Exception("'$prop' is not a valid CSS2 property.");
703
+
704
+ if ( isset($this->_prop_cache[$prop]) && $this->_prop_cache[$prop] != null )
705
+ return $this->_prop_cache[$prop];
706
+
707
+ $method = "get_$prop";
708
+
709
+ // Fall back on defaults if property is not set
710
+ if ( !isset($this->_props[$prop]) )
711
+ $this->_props[$prop] = self::$_defaults[$prop];
712
+
713
+ if ( !isset(self::$_methods_cache[$method]) ) {
714
+ self::$_methods_cache[$method] = method_exists($this, $method);
715
+ }
716
+
717
+ if ( self::$_methods_cache[$method] )
718
+ return $this->_prop_cache[$prop] = $this->$method();
719
+
720
+ return $this->_prop_cache[$prop] = $this->_props[$prop];
721
+ }
722
+
723
+ function get_font_family_raw(){
724
+ return trim($this->_props["font_family"], " \t\n\r\x0B\"'");
725
+ }
726
+
727
+ /**
728
+ * Getter for the 'font-family' CSS property.
729
+ *
730
+ * Uses the {@link Font_Metrics} class to resolve the font family into an
731
+ * actual font file.
732
+ *
733
+ * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-family
734
+ * @return string
735
+ */
736
+ function get_font_family() {
737
+
738
+ $DEBUGCSS=DEBUGCSS; //=DEBUGCSS; Allow override of global setting for ad hoc debug
739
+
740
+ // Select the appropriate font. First determine the subtype, then check
741
+ // the specified font-families for a candidate.
742
+
743
+ // Resolve font-weight
744
+ $weight = $this->__get("font_weight");
745
+
746
+ if ( is_numeric($weight) ) {
747
+
748
+ if ( $weight < 600 )
749
+ $weight = "normal";
750
+ else
751
+ $weight = "bold";
752
+
753
+ } else if ( $weight === "bold" || $weight === "bolder" ) {
754
+ $weight = "bold";
755
+
756
+ } else {
757
+ $weight = "normal";
758
+
759
+ }
760
+
761
+ // Resolve font-style
762
+ $font_style = $this->__get("font_style");
763
+
764
+ if ( $weight === "bold" && ($font_style === "italic" || $font_style === "oblique") )
765
+ $subtype = "bold_italic";
766
+ else if ( $weight === "bold" && $font_style !== "italic" && $font_style !== "oblique" )
767
+ $subtype = "bold";
768
+ else if ( $weight !== "bold" && ($font_style === "italic" || $font_style === "oblique") )
769
+ $subtype = "italic";
770
+ else
771
+ $subtype = "normal";
772
+
773
+ // Resolve the font family
774
+ if ($DEBUGCSS) {
775
+ print "<pre>[get_font_family:";
776
+ print '('.$this->_props["font_family"].'.'.$font_style.'.'.$this->__get("font_weight").'.'.$weight.'.'.$subtype.')';
777
+ }
778
+ $families = explode(",", $this->_props["font_family"]);
779
+ $families = array_map('trim',$families);
780
+ reset($families);
781
+
782
+ $font = null;
783
+ while ( current($families) ) {
784
+ list(,$family) = each($families);
785
+ //remove leading and trailing string delimiters, e.g. on font names with spaces;
786
+ //remove leading and trailing whitespace
787
+ $family = trim($family, " \t\n\r\x0B\"'");
788
+ if ($DEBUGCSS) print '('.$family.')';
789
+ $font = Font_Metrics::get_font($family, $subtype);
790
+
791
+ if ( $font ) {
792
+ if ($DEBUGCSS) print '('.$font.")get_font_family]\n</pre>";
793
+ return $font;
794
+ }
795
+ }
796
+
797
+ $family = null;
798
+ if ($DEBUGCSS) print '(default)';
799
+ $font = Font_Metrics::get_font($family, $subtype);
800
+
801
+ if ( $font ) {
802
+ if ($DEBUGCSS) print '('.$font.")get_font_family]\n</pre>";
803
+ return $font;
804
+ }
805
+ throw new DOMPDF_Exception("Unable to find a suitable font replacement for: '" . $this->_props["font_family"] ."'");
806
+
807
+ }
808
+
809
+ /**
810
+ * Returns the resolved font size, in points
811
+ *
812
+ * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size
813
+ * @return float
814
+ */
815
+ function get_font_size() {
816
+
817
+ if ( $this->__font_size_calculated )
818
+ return $this->_props["font_size"];
819
+
820
+ if ( !isset($this->_props["font_size"]) )
821
+ $fs = self::$_defaults["font_size"];
822
+ else
823
+ $fs = $this->_props["font_size"];
824
+
825
+ if ( !isset($this->_parent_font_size) )
826
+ $this->_parent_font_size = self::$default_font_size;
827
+
828
+ switch ($fs) {
829
+ case "xx-small":
830
+ case "x-small":
831
+ case "small":
832
+ case "medium":
833
+ case "large":
834
+ case "x-large":
835
+ case "xx-large":
836
+ $fs = self::$default_font_size * self::$font_size_keywords[$fs];
837
+ break;
838
+
839
+ case "smaller":
840
+ $fs = 8/9 * $this->_parent_font_size;
841
+ break;
842
+
843
+ case "larger":
844
+ $fs = 6/5 * $this->_parent_font_size;
845
+ break;
846
+
847
+ default:
848
+ break;
849
+ }
850
+
851
+ // Ensure relative sizes resolve to something
852
+ if ( ($i = mb_strpos($fs, "em")) !== false )
853
+ $fs = mb_substr($fs, 0, $i) * $this->_parent_font_size;
854
+
855
+ else if ( ($i = mb_strpos($fs, "ex")) !== false )
856
+ $fs = mb_substr($fs, 0, $i) * $this->_parent_font_size;
857
+
858
+ else
859
+ $fs = $this->length_in_pt($fs);
860
+
861
+ //see __set and __get, on all assignments clear cache!
862
+ $this->_prop_cache["font_size"] = null;
863
+ $this->_props["font_size"] = $fs;
864
+ $this->__font_size_calculated = true;
865
+ return $this->_props["font_size"];
866
+
867
+ }
868
+
869
+ /**
870
+ * @link http://www.w3.org/TR/CSS21/text.html#propdef-word-spacing
871
+ * @return float
872
+ */
873
+ function get_word_spacing() {
874
+ if ( $this->_props["word_spacing"] === "normal" )
875
+ return 0;
876
+
877
+ return $this->_props["word_spacing"];
878
+ }
879
+
880
+ /**
881
+ * @link http://www.w3.org/TR/CSS21/text.html#propdef-letter-spacing
882
+ * @return float
883
+ */
884
+ function get_letter_spacing() {
885
+ if ( $this->_props["letter_spacing"] === "normal" )
886
+ return 0;
887
+
888
+ return $this->_props["letter_spacing"];
889
+ }
890
+
891
+ /**
892
+ * @link http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height
893
+ * @return float
894
+ */
895
+ function get_line_height() {
896
+ $line_height = $this->_props["line_height"];
897
+
898
+ if ( $line_height === "normal" )
899
+ return self::$default_line_height * $this->get_font_size();
900
+
901
+ if ( is_numeric($line_height) )
902
+ return $this->length_in_pt( $line_height . "em", $this->get_font_size());
903
+
904
+ return $this->length_in_pt( $line_height, $this->get_font_size() );
905
+ }
906
+
907
+ /**
908
+ * Returns the colour as an array
909
+ *
910
+ * The array has the following format:
911
+ * <code>array(r,g,b, "r" => r, "g" => g, "b" => b, "hex" => "#rrggbb")</code>
912
+ *
913
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color
914
+ * @return array
915
+ */
916
+ function get_color() {
917
+ return $this->munge_color( $this->_props["color"] );
918
+ }
919
+
920
+ /**
921
+ * Returns the background colour as an array
922
+ *
923
+ * The returned array has the same format as {@link Style::get_color()}
924
+ *
925
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color
926
+ * @return array
927
+ */
928
+ function get_background_color() {
929
+ return $this->munge_color( $this->_props["background_color"] );
930
+ }
931
+
932
+ /**
933
+ * Returns the background position as an array
934
+ *
935
+ * The returned array has the following format:
936
+ * <code>array(x,y, "x" => x, "y" => y)</code>
937
+ *
938
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position
939
+ * @return array
940
+ */
941
+ function get_background_position() {
942
+ $tmp = explode(" ", $this->_props["background_position"]);
943
+
944
+ switch ($tmp[0]) {
945
+
946
+ case "left":
947
+ $x = "0%";
948
+ break;
949
+
950
+ case "right":
951
+ $x = "100%";
952
+ break;
953
+
954
+ case "top":
955
+ $y = "0%";
956
+ break;
957
+
958
+ case "bottom":
959
+ $y = "100%";
960
+ break;
961
+
962
+ case "center":
963
+ $x = "50%";
964
+ $y = "50%";
965
+ break;
966
+
967
+ default:
968
+ $x = $tmp[0];
969
+ break;
970
+ }
971
+
972
+ if ( isset($tmp[1]) ) {
973
+
974
+ switch ($tmp[1]) {
975
+ case "left":
976
+ $x = "0%";
977
+ break;
978
+
979
+ case "right":
980
+ $x = "100%";
981
+ break;
982
+
983
+ case "top":
984
+ $y = "0%";
985
+ break;
986
+
987
+ case "bottom":
988
+ $y = "100%";
989
+ break;
990
+
991
+ case "center":
992
+ if ( $tmp[0] === "left" || $tmp[0] === "right" || $tmp[0] === "center" )
993
+ $y = "50%";
994
+ else
995
+ $x = "50%";
996
+ break;
997
+
998
+ default:
999
+ $y = $tmp[1];
1000
+ break;
1001
+ }
1002
+
1003
+ } else {
1004
+ $y = "50%";
1005
+ }
1006
+
1007
+ if ( !isset($x) )
1008
+ $x = "0%";
1009
+
1010
+ if ( !isset($y) )
1011
+ $y = "0%";
1012
+
1013
+ return array( 0 => $x, "x" => $x,
1014
+ 1 => $y, "y" => $y );
1015
+ }
1016
+
1017
+
1018
+ /**
1019
+ * Returns the background as it is currently stored
1020
+ *
1021
+ * (currently anyway only for completeness.
1022
+ * not used for further processing)
1023
+ *
1024
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment
1025
+ * @return string
1026
+ */
1027
+ function get_background_attachment() {
1028
+ return $this->_props["background_attachment"];
1029
+ }
1030
+
1031
+
1032
+ /**
1033
+ * Returns the background_repeat as it is currently stored
1034
+ *
1035
+ * (currently anyway only for completeness.
1036
+ * not used for further processing)
1037
+ *
1038
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat
1039
+ * @return string
1040
+ */
1041
+ function get_background_repeat() {
1042
+ return $this->_props["background_repeat"];
1043
+ }
1044
+
1045
+
1046
+ /**
1047
+ * Returns the background as it is currently stored
1048
+ *
1049
+ * (currently anyway only for completeness.
1050
+ * not used for further processing, but the individual get_background_xxx)
1051
+ *
1052
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background
1053
+ * @return string
1054
+ */
1055
+ function get_background() {
1056
+ return $this->_props["background"];
1057
+ }
1058
+
1059
+
1060
+ /**#@+
1061
+ * Returns the border colour as an array
1062
+ *
1063
+ * See {@link Style::get_color()}
1064
+ *
1065
+ * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties
1066
+ * @return array
1067
+ */
1068
+ function get_border_top_color() {
1069
+ if ( $this->_props["border_top_color"] === "" ) {
1070
+ //see __set and __get, on all assignments clear cache!
1071
+ $this->_prop_cache["border_top_color"] = null;
1072
+ $this->_props["border_top_color"] = $this->__get("color");
1073
+ }
1074
+ return $this->munge_color($this->_props["border_top_color"]);
1075
+ }
1076
+
1077
+ function get_border_right_color() {
1078
+ if ( $this->_props["border_right_color"] === "" ) {
1079
+ //see __set and __get, on all assignments clear cache!
1080
+ $this->_prop_cache["border_right_color"] = null;
1081
+ $this->_props["border_right_color"] = $this->__get("color");
1082
+ }
1083
+ return $this->munge_color($this->_props["border_right_color"]);
1084
+ }
1085
+
1086
+ function get_border_bottom_color() {
1087
+ if ( $this->_props["border_bottom_color"] === "" ) {
1088
+ //see __set and __get, on all assignments clear cache!
1089
+ $this->_prop_cache["border_bottom_color"] = null;
1090
+ $this->_props["border_bottom_color"] = $this->__get("color");
1091
+ }
1092
+ return $this->munge_color($this->_props["border_bottom_color"]);
1093
+ }
1094
+
1095
+ function get_border_left_color() {
1096
+ if ( $this->_props["border_left_color"] === "" ) {
1097
+ //see __set and __get, on all assignments clear cache!
1098
+ $this->_prop_cache["border_left_color"] = null;
1099
+ $this->_props["border_left_color"] = $this->__get("color");
1100
+ }
1101
+ return $this->munge_color($this->_props["border_left_color"]);
1102
+ }
1103
+
1104
+ /**#@-*/
1105
+
1106
+ /**#@+
1107
+ * Returns the border width, as it is currently stored
1108
+ *
1109
+ * @link http://www.w3.org/TR/CSS21/box.html#border-width-properties
1110
+ * @return float|string
1111
+ */
1112
+ function get_border_top_width() {
1113
+ $style = $this->__get("border_top_style");
1114
+ return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_top_width"]) : 0;
1115
+ }
1116
+
1117
+ function get_border_right_width() {
1118
+ $style = $this->__get("border_right_style");
1119
+ return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_right_width"]) : 0;
1120
+ }
1121
+
1122
+ function get_border_bottom_width() {
1123
+ $style = $this->__get("border_bottom_style");
1124
+ return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_bottom_width"]) : 0;
1125
+ }
1126
+
1127
+ function get_border_left_width() {
1128
+ $style = $this->__get("border_left_style");
1129
+ return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_left_width"]) : 0;
1130
+ }
1131
+ /**#@-*/
1132
+
1133
+ /**
1134
+ * Return an array of all border properties.
1135
+ *
1136
+ * The returned array has the following structure:
1137
+ * <code>
1138
+ * array("top" => array("width" => [border-width],
1139
+ * "style" => [border-style],
1140
+ * "color" => [border-color (array)]),
1141
+ * "bottom" ... )
1142
+ * </code>
1143
+ *
1144
+ * @return array
1145
+ */
1146
+ function get_border_properties() {
1147
+ return array("top" => array("width" => $this->__get("border_top_width"),
1148
+ "style" => $this->__get("border_top_style"),
1149
+ "color" => $this->__get("border_top_color")),
1150
+ "bottom" => array("width" => $this->__get("border_bottom_width"),
1151
+ "style" => $this->__get("border_bottom_style"),
1152
+ "color" => $this->__get("border_bottom_color")),
1153
+ "right" => array("width" => $this->__get("border_right_width"),
1154
+ "style" => $this->__get("border_right_style"),
1155
+ "color" => $this->__get("border_right_color")),
1156
+ "left" => array("width" => $this->__get("border_left_width"),
1157
+ "style" => $this->__get("border_left_style"),
1158
+ "color" => $this->__get("border_left_color")));
1159
+ }
1160
+
1161
+ /**
1162
+ * Return a single border property
1163
+ *
1164
+ * @return mixed
1165
+ */
1166
+ protected function _get_border($side) {
1167
+ $color = $this->__get("border_" . $side . "_color");
1168
+
1169
+ return $this->__get("border_" . $side . "_width") . " " .
1170
+ $this->__get("border_" . $side . "_style") . " " . $color["hex"];
1171
+ }
1172
+
1173
+ /**#@+
1174
+ * Return full border properties as a string
1175
+ *
1176
+ * Border properties are returned just as specified in CSS:
1177
+ * <pre>[width] [style] [color]</pre>
1178
+ * e.g. "1px solid blue"
1179
+ *
1180
+ * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties
1181
+ * @return string
1182
+ */
1183
+ function get_border_top() { return $this->_get_border("top"); }
1184
+ function get_border_right() { return $this->_get_border("right"); }
1185
+ function get_border_bottom() { return $this->_get_border("bottom"); }
1186
+ function get_border_left() { return $this->_get_border("left"); }
1187
+ /**#@-*/
1188
+
1189
+ /**
1190
+ * Returns the outline colour as an array
1191
+ *
1192
+ * See {@link Style::get_color()}
1193
+ *
1194
+ * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties
1195
+ * @return array
1196
+ */
1197
+ function get_outline_color() {
1198
+ if ( $this->_props["outline_color"] === "" ) {
1199
+ //see __set and __get, on all assignments clear cache!
1200
+ $this->_prop_cache["outline_color"] = null;
1201
+ $this->_props["outline_color"] = $this->__get("color");
1202
+ }
1203
+ return $this->munge_color($this->_props["outline_color"]);
1204
+ }
1205
+
1206
+ /**#@+
1207
+ * Returns the outline width, as it is currently stored
1208
+ * @return float|string
1209
+ */
1210
+ function get_outline_width() {
1211
+ $style = $this->__get("outline_style");
1212
+ return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["outline_width"]) : 0;
1213
+ }
1214
+
1215
+ /**#@+
1216
+ * Return full outline properties as a string
1217
+ *
1218
+ * Outline properties are returned just as specified in CSS:
1219
+ * <pre>[width] [style] [color]</pre>
1220
+ * e.g. "1px solid blue"
1221
+ *
1222
+ * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties
1223
+ * @return string
1224
+ */
1225
+ function get_outline() {
1226
+ $color = $this->__get("outline_color");
1227
+ return
1228
+ $this->__get("outline_width") . " " .
1229
+ $this->__get("outline_style") . " " .
1230
+ $color["hex"];
1231
+ }
1232
+ /**#@-*/
1233
+
1234
+ /**
1235
+ * Returns border spacing as an array
1236
+ *
1237
+ * The array has the format (h_space,v_space)
1238
+ *
1239
+ * @link http://www.w3.org/TR/CSS21/tables.html#propdef-border-spacing
1240
+ * @return array
1241
+ */
1242
+ function get_border_spacing() {
1243
+ return explode(" ", $this->_props["border_spacing"]);
1244
+ }
1245
+
1246
+ /*==============================*/
1247
+
1248
+ /*
1249
+ !important attribute
1250
+ For basic functionality of the !important attribute with overloading
1251
+ of several styles of an element, changes in inherit(), merge() and _parse_properties()
1252
+ are sufficient [helpers var $_important_props, __construct(), important_set(), important_get()]
1253
+
1254
+ Only for combined attributes extra treatment needed. See below.
1255
+
1256
+ div { border: 1px red; }
1257
+ div { border: solid; } // Not combined! Only one occurence of same style per context
1258
+ //
1259
+ div { border: 1px red; }
1260
+ div a { border: solid; } // Adding to border style ok by inheritance
1261
+ //
1262
+ div { border-style: solid; } // Adding to border style ok because of different styles
1263
+ div { border: 1px red; }
1264
+ //
1265
+ div { border-style: solid; !important} // border: overrides, even though not !important
1266
+ div { border: 1px dashed red; }
1267
+ //
1268
+ div { border: 1px red; !important }
1269
+ div a { border-style: solid; } // Need to override because not set
1270
+
1271
+ Special treatment:
1272
+ At individual property like border-top-width need to check whether overriding value is also !important.
1273
+ Also store the !important condition for later overrides.
1274
+ Since not known who is initiating the override, need to get passed !importan as parameter.
1275
+ !important Paramter taken as in the original style in the css file.
1276
+ When poperty border !important given, do not mark subsets like border_style as important. Only
1277
+ individual properties.
1278
+
1279
+ Note:
1280
+ Setting individual property directly from css with e.g. set_border_top_style() is not needed, because
1281
+ missing set funcions handled by a generic handler __set(), including the !important.
1282
+ Setting individual property of as sub-property is handled below.
1283
+
1284
+ Implementation see at _set_style_side_type()
1285
+ Callers _set_style_sides_type(), _set_style_type, _set_style_type_important()
1286
+
1287
+ Related functionality for background, padding, margin, font, list_style
1288
+ */
1289
+
1290
+ /* Generalized set function for individual attribute of combined style.
1291
+ * With check for !important
1292
+ * Applicable for background, border, padding, margin, font, list_style
1293
+ * Note: $type has a leading underscore (or is empty), the others not.
1294
+ */
1295
+ protected function _set_style_side_type($style,$side,$type,$val,$important) {
1296
+ $prop = $style.'_'.$side.$type;
1297
+
1298
+ if ( !isset($this->_important_props[$prop]) || $important) {
1299
+ //see __set and __get, on all assignments clear cache!
1300
+ $this->_prop_cache[$prop] = null;
1301
+ if ($important) {
1302
+ $this->_important_props[$prop] = true;
1303
+ }
1304
+ $this->_props[$prop] = $val;
1305
+ }
1306
+ }
1307
+
1308
+ protected function _set_style_sides_type($style,$top,$right,$bottom,$left,$type,$important) {
1309
+ $this->_set_style_side_type($style,'top',$type,$top,$important);
1310
+ $this->_set_style_side_type($style,'right',$type,$right,$important);
1311
+ $this->_set_style_side_type($style,'bottom',$type,$bottom,$important);
1312
+ $this->_set_style_side_type($style,'left',$type,$left,$important);
1313
+ }
1314
+
1315
+ protected function _set_style_type($style,$type,$val,$important) {
1316
+ $val = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces
1317
+ $arr = explode(" ", $val);
1318
+
1319
+ switch (count($arr)) {
1320
+ case 1:
1321
+ $this->_set_style_sides_type($style,$arr[0],$arr[0],$arr[0],$arr[0],$type,$important);
1322
+ break;
1323
+ case 2:
1324
+ $this->_set_style_sides_type($style,$arr[0],$arr[1],$arr[0],$arr[1],$type,$important);
1325
+ break;
1326
+ case 3:
1327
+ $this->_set_style_sides_type($style,$arr[0],$arr[1],$arr[2],$arr[1],$type,$important);
1328
+ break;
1329
+ case 4:
1330
+ $this->_set_style_sides_type($style,$arr[0],$arr[1],$arr[2],$arr[3],$type,$important);
1331
+ break;
1332
+ default:
1333
+ break;
1334
+ }
1335
+ //see __set and __get, on all assignments clear cache!
1336
+ $this->_prop_cache[$style.$type] = null;
1337
+ $this->_props[$style.$type] = $val;
1338
+ }
1339
+
1340
+ protected function _set_style_type_important($style,$type,$val) {
1341
+ $this->_set_style_type($style,$type,$val,isset($this->_important_props[$style.$type]));
1342
+ }
1343
+
1344
+ /* Anyway only called if _important matches and is assigned
1345
+ * E.g. _set_style_side_type($style,$side,'',str_replace("none", "0px", $val),isset($this->_important_props[$style.'_'.$side]));
1346
+ */
1347
+ protected function _set_style_side_width_important($style,$side,$val) {
1348
+ //see __set and __get, on all assignments clear cache!
1349
+ $this->_prop_cache[$style.'_'.$side] = null;
1350
+ $this->_props[$style.'_'.$side] = str_replace("none", "0px", $val);
1351
+ }
1352
+
1353
+ protected function _set_style($style,$val,$important) {
1354
+ if ( !isset($this->_important_props[$style]) || $important) {
1355
+ if ($important) {
1356
+ $this->_important_props[$style] = true;
1357
+ }
1358
+ //see __set and __get, on all assignments clear cache!
1359
+ $this->_prop_cache[$style] = null;
1360
+ $this->_props[$style] = $val;
1361
+ }
1362
+ }
1363
+
1364
+ protected function _image($val) {
1365
+ $DEBUGCSS=DEBUGCSS;
1366
+
1367
+ if ( mb_strpos($val, "url") === false ) {
1368
+ $path = "none"; //Don't resolve no image -> otherwise would prefix path and no longer recognize as none
1369
+ } else {
1370
+ $val = preg_replace("/url\(['\"]?([^'\")]+)['\"]?\)/","\\1", trim($val));
1371
+
1372
+ // Resolve the url now in the context of the current stylesheet
1373
+ $parsed_url = explode_url($val);
1374
+ if ( $parsed_url["protocol"] == "" && $this->_stylesheet->get_protocol() == "" ) {
1375
+ if ($parsed_url["path"][0] === '/' || $parsed_url["path"][0] === '\\' ) {
1376
+ $path = $_SERVER["DOCUMENT_ROOT"].'/';
1377
+ } else {
1378
+ $path = $this->_stylesheet->get_base_path();
1379
+ }
1380
+ $path .= $parsed_url["path"] . $parsed_url["file"];
1381
+ $path = realpath($path);
1382
+ // If realpath returns FALSE then specifically state that there is no background image
1383
+ if (!$path) { $path = 'none'; }
1384
+ } else {
1385
+ $path = build_url($this->_stylesheet->get_protocol(),
1386
+ $this->_stylesheet->get_host(),
1387
+ $this->_stylesheet->get_base_path(),
1388
+ $val);
1389
+ }
1390
+ }
1391
+ if ($DEBUGCSS) {
1392
+ print "<pre>[_image\n";
1393
+ print_r($parsed_url);
1394
+ print $this->_stylesheet->get_protocol()."\n".$this->_stylesheet->get_base_path()."\n".$path."\n";
1395
+ print "_image]</pre>";;
1396
+ }
1397
+ return $path;
1398
+ }
1399
+
1400
+ /*======================*/
1401
+
1402
+ /**
1403
+ * Sets colour
1404
+ *
1405
+ * The colour parameter can be any valid CSS colour value
1406
+ *
1407
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color
1408
+ * @param string $colour
1409
+ */
1410
+ function set_color($colour) {
1411
+ $col = $this->munge_colour($colour);
1412
+
1413
+ if ( is_null($col) )
1414
+ $col = self::$_defaults["color"];
1415
+
1416
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1417
+ $this->_prop_cache["color"] = null;
1418
+ $this->_props["color"] = $col["hex"];
1419
+ }
1420
+
1421
+ /**
1422
+ * Sets the background colour
1423
+ *
1424
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color
1425
+ * @param string $colour
1426
+ */
1427
+ function set_background_color($colour) {
1428
+ $col = $this->munge_colour($colour);
1429
+ if ( is_null($col) )
1430
+ $col = self::$_defaults["background_color"];
1431
+
1432
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1433
+ $this->_prop_cache["background_color"] = null;
1434
+ $this->_props["background_color"] = is_array($col) ? $col["hex"] : $col;
1435
+ }
1436
+
1437
+ /**
1438
+ * Set the background image url
1439
+ *
1440
+ * @link http://www.w3.org/TR/CSS21/colors.html#background-properties
1441
+ * @param string $url
1442
+ */
1443
+ function set_background_image($val) {
1444
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1445
+ $this->_prop_cache["background_image"] = null;
1446
+ $this->_props["background_image"] = $this->_image($val);
1447
+ }
1448
+
1449
+ /**
1450
+ * Sets the background repeat
1451
+ *
1452
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat
1453
+ * @param string $val
1454
+ */
1455
+ function set_background_repeat($val) {
1456
+ if ( is_null($val) )
1457
+ $val = self::$_defaults["background_repeat"];
1458
+
1459
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1460
+ $this->_prop_cache["background_repeat"] = null;
1461
+ $this->_props["background_repeat"] = $val;
1462
+ }
1463
+
1464
+ /**
1465
+ * Sets the background attachment
1466
+ *
1467
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment
1468
+ * @param string $val
1469
+ */
1470
+ function set_background_attachment($val) {
1471
+ if ( is_null($val) )
1472
+ $val = self::$_defaults["background_attachment"];
1473
+
1474
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1475
+ $this->_prop_cache["background_attachment"] = null;
1476
+ $this->_props["background_attachment"] = $val;
1477
+ }
1478
+
1479
+ /**
1480
+ * Sets the background position
1481
+ *
1482
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position
1483
+ * @param string $val
1484
+ */
1485
+ function set_background_position($val) {
1486
+ if ( is_null($val) )
1487
+ $val = self::$_defaults["background_position"];
1488
+
1489
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1490
+ $this->_prop_cache["background_position"] = null;
1491
+ $this->_props["background_position"] = $val;
1492
+ }
1493
+
1494
+ /**
1495
+ * Sets the background - combined options
1496
+ *
1497
+ * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background
1498
+ * @param string $val
1499
+ */
1500
+ function set_background($val) {
1501
+ $col = null;
1502
+ $pos = array();
1503
+ $tmp = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces
1504
+ $tmp = explode(" ", $tmp);
1505
+ $important = isset($this->_important_props["background"]);
1506
+
1507
+ foreach($tmp as $attr) {
1508
+ if (mb_substr($attr, 0, 3) === "url" || $attr === "none") {
1509
+ $this->_set_style("background_image", $this->_image($attr), $important);
1510
+ } else if ($attr === "fixed" || $attr === "scroll") {
1511
+ $this->_set_style("background_attachment", $attr, $important);
1512
+ } else if ($attr === "repeat" || $attr === "repeat-x" || $attr === "repeat-y" || $attr === "no-repeat") {
1513
+ $this->_set_style("background_repeat", $attr, $important);
1514
+ } else if (($col = $this->munge_color($attr)) != null ) {
1515
+ $this->_set_style("background_color", is_array($col) ? $col["hex"] : $col, $important);
1516
+ } else {
1517
+ $pos[] = $attr;
1518
+ }
1519
+ }
1520
+
1521
+ if (count($pos)) {
1522
+ $this->_set_style("background_position",implode(' ',$pos), $important);
1523
+ }
1524
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1525
+ $this->_prop_cache["background"] = null;
1526
+ $this->_props["background"] = $val;
1527
+ }
1528
+
1529
+ /**
1530
+ * Sets the font size
1531
+ *
1532
+ * $size can be any acceptable CSS size
1533
+ *
1534
+ * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size
1535
+ * @param string|float $size
1536
+ */
1537
+ function set_font_size($size) {
1538
+ $this->__font_size_calculated = false;
1539
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1540
+ $this->_prop_cache["font_size"] = null;
1541
+ $this->_props["font_size"] = $size;
1542
+ }
1543
+
1544
+ /**
1545
+ * Sets the font style
1546
+ *
1547
+ * combined attributes
1548
+ * set individual attributes also, respecting !important mark
1549
+ * exactly this order, separate by space. Multiple fonts separated by comma:
1550
+ * font-style, font-variant, font-weight, font-size, line-height, font-family
1551
+ *
1552
+ * Other than with border and list, existing partial attributes should
1553
+ * reset when starting here, even when not mentioned.
1554
+ * If individual attribute is !important and explicite or implicite replacement is not,
1555
+ * keep individual attribute
1556
+ *
1557
+ * require whitespace as delimiters for single value attributes
1558
+ * On delimiter "/" treat first as font height, second as line height
1559
+ * treat all remaining at the end of line as font
1560
+ * font-style, font-variant, font-weight, font-size, line-height, font-family
1561
+ *
1562
+ * missing font-size and font-family might be not allowed, but accept it here and
1563
+ * use default (medium size, enpty font name)
1564
+ *
1565
+ * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style
1566
+ * @param $val
1567
+ */
1568
+ function set_font($val) {
1569
+ $this->__font_size_calculated = false;
1570
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1571
+ $this->_prop_cache["font"] = null;
1572
+ $this->_props["font"] = $val;
1573
+
1574
+ $important = isset($this->_important_props["font"]);
1575
+
1576
+ if ( preg_match("/^(italic|oblique|normal)\s*(.*)$/i",$val,$match) ) {
1577
+ $this->_set_style("font_style", $match[1], $important);
1578
+ $val = $match[2];
1579
+ } else {
1580
+ $this->_set_style("font_style", self::$_defaults["font_style"], $important);
1581
+ }
1582
+
1583
+ if ( preg_match("/^(small-caps|normal)\s*(.*)$/i",$val,$match) ) {
1584
+ $this->_set_style("font_variant", $match[1], $important);
1585
+ $val = $match[2];
1586
+ } else {
1587
+ $this->_set_style("font_variant", self::$_defaults["font_variant"], $important);
1588
+ }
1589
+
1590
+ //matching numeric value followed by unit -> this is indeed a subsequent font size. Skip!
1591
+ if ( preg_match("/^(bold|bolder|lighter|100|200|300|400|500|600|700|800|900|normal)\s*(.*)$/i",$val,$match) &&
1592
+ !preg_match("/^(?:pt|px|pc|em|ex|in|cm|mm|%)/",$match[2])
1593
+ ) {
1594
+ $this->_set_style("font_weight", $match[1], $important);
1595
+ $val = $match[2];
1596
+ } else {
1597
+ $this->_set_style("font_weight", self::$_defaults["font_weight"], $important);
1598
+ }
1599
+
1600
+ 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) ) {
1601
+ $this->_set_style("font_size", $match[1], $important);
1602
+ $val = $match[2];
1603
+ if (preg_match("/^\/\s*(\d+\s*(?:pt|px|pc|em|ex|in|cm|mm|%))\s*(.*)$/i",$val,$match) ) {
1604
+ $this->_set_style("line_height", $match[1], $important);
1605
+ $val = $match[2];
1606
+ } else {
1607
+ $this->_set_style("line_height", self::$_defaults["line_height"], $important);
1608
+ }
1609
+ } else {
1610
+ $this->_set_style("font_size", self::$_defaults["font_size"], $important);
1611
+ $this->_set_style("line_height", self::$_defaults["line_height"], $important);
1612
+ }
1613
+
1614
+ if(strlen($val) != 0) {
1615
+ $this->_set_style("font_family", $val, $important);
1616
+ } else {
1617
+ $this->_set_style("font_family", self::$_defaults["font_family"], $important);
1618
+ }
1619
+ }
1620
+
1621
+ /**#@+
1622
+ * Sets page break properties
1623
+ *
1624
+ * @link http://www.w3.org/TR/CSS21/page.html#page-breaks
1625
+ * @param string $break
1626
+ */
1627
+ function set_page_break_before($break) {
1628
+ if ($break === "left" || $break === "right")
1629
+ $break = "always";
1630
+
1631
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1632
+ $this->_prop_cache["page_break_before"] = null;
1633
+ $this->_props["page_break_before"] = $break;
1634
+ }
1635
+
1636
+ function set_page_break_after($break) {
1637
+ if ($break === "left" || $break === "right")
1638
+ $break = "always";
1639
+
1640
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1641
+ $this->_prop_cache["page_break_after"] = null;
1642
+ $this->_props["page_break_after"] = $break;
1643
+ }
1644
+ /**#@-*/
1645
+
1646
+ //........................................................................
1647
+
1648
+ /**#@+
1649
+ * Sets the margin size
1650
+ *
1651
+ * @link http://www.w3.org/TR/CSS21/box.html#margin-properties
1652
+ * @param $val
1653
+ */
1654
+ function set_margin_top($val) {
1655
+ $this->_set_style_side_width_important('margin','top',$val);
1656
+ }
1657
+
1658
+ function set_margin_right($val) {
1659
+ $this->_set_style_side_width_important('margin','right',$val);
1660
+ }
1661
+
1662
+ function set_margin_bottom($val) {
1663
+ $this->_set_style_side_width_important('margin','bottom',$val);
1664
+ }
1665
+
1666
+ function set_margin_left($val) {
1667
+ $this->_set_style_side_width_important('margin','left',$val);
1668
+ }
1669
+
1670
+ function set_margin($val) {
1671
+ $val = str_replace("none", "0px", $val);
1672
+ $this->_set_style_type_important('margin','',$val);
1673
+ }
1674
+ /**#@-*/
1675
+
1676
+ /**#@+
1677
+ * Sets the padding size
1678
+ *
1679
+ * @link http://www.w3.org/TR/CSS21/box.html#padding-properties
1680
+ * @param $val
1681
+ */
1682
+ function set_padding_top($val) {
1683
+ $this->_set_style_side_width_important('padding','top',$val);
1684
+ }
1685
+
1686
+ function set_padding_right($val) {
1687
+ $this->_set_style_side_width_important('padding','right',$val);
1688
+ }
1689
+
1690
+ function set_padding_bottom($val) {
1691
+ $this->_set_style_side_width_important('padding','bottom',$val);
1692
+ }
1693
+
1694
+ function set_padding_left($val) {
1695
+ $this->_set_style_side_width_important('padding','left',$val);
1696
+ }
1697
+
1698
+ function set_padding($val) {
1699
+ $val = str_replace("none", "0px", $val);
1700
+ $this->_set_style_type_important('padding','',$val);
1701
+ }
1702
+ /**#@-*/
1703
+
1704
+ /**
1705
+ * Sets a single border
1706
+ *
1707
+ * @param string $side
1708
+ * @param string $border_spec ([width] [style] [color])
1709
+ */
1710
+ protected function _set_border($side, $border_spec, $important) {
1711
+ $border_spec = preg_replace("/\s*\,\s*/", ",", $border_spec);
1712
+ //$border_spec = str_replace(",", " ", $border_spec); // Why did we have this ?? rbg(10, 102, 10) > rgb(10 102 10)
1713
+ $arr = explode(" ", $border_spec);
1714
+
1715
+ // FIXME: handle partial values
1716
+
1717
+ //For consistency of individal and combined properties, and with ie8 and firefox3
1718
+ //reset all attributes, even if only partially given
1719
+ $this->_set_style_side_type('border',$side,'_style',self::$_defaults['border_'.$side.'_style'],$important);
1720
+ $this->_set_style_side_type('border',$side,'_width',self::$_defaults['border_'.$side.'_width'],$important);
1721
+ $this->_set_style_side_type('border',$side,'_color',self::$_defaults['border_'.$side.'_color'],$important);
1722
+
1723
+ foreach ($arr as $value) {
1724
+ $value = trim($value);
1725
+ if ( in_array($value, self::$BORDER_STYLES) ) {
1726
+ $this->_set_style_side_type('border',$side,'_style',$value,$important);
1727
+
1728
+ } else if ( preg_match("/[.0-9]+(?:px|pt|pc|em|ex|%|in|mm|cm)|(?:thin|medium|thick)/", $value ) ) {
1729
+ $this->_set_style_side_type('border',$side,'_width',$value,$important);
1730
+
1731
+ } else {
1732
+ // must be colour
1733
+ $this->_set_style_side_type('border',$side,'_color',$value,$important);
1734
+ }
1735
+ }
1736
+
1737
+ //see __set and __get, on all assignments clear cache!
1738
+ $this->_prop_cache['border_'.$side] = null;
1739
+ $this->_props['border_'.$side] = $border_spec;
1740
+ }
1741
+
1742
+ /**#@+
1743
+ * Sets the border styles
1744
+ *
1745
+ * @link http://www.w3.org/TR/CSS21/box.html#border-properties
1746
+ * @param string $val
1747
+ */
1748
+ function set_border_top($val) { $this->_set_border("top", $val, isset($this->_important_props['border_top'])); }
1749
+ function set_border_right($val) { $this->_set_border("right", $val, isset($this->_important_props['border_right'])); }
1750
+ function set_border_bottom($val) { $this->_set_border("bottom", $val, isset($this->_important_props['border_bottom'])); }
1751
+ function set_border_left($val) { $this->_set_border("left", $val, isset($this->_important_props['border_left'])); }
1752
+
1753
+ function set_border($val) {
1754
+ $important = isset($this->_important_props["border"]);
1755
+ $this->_set_border("top", $val, $important);
1756
+ $this->_set_border("right", $val, $important);
1757
+ $this->_set_border("bottom", $val, $important);
1758
+ $this->_set_border("left", $val, $important);
1759
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1760
+ $this->_prop_cache["border"] = null;
1761
+ $this->_props["border"] = $val;
1762
+ }
1763
+
1764
+ function set_border_width($val) {
1765
+ $this->_set_style_type_important('border','_width',$val);
1766
+ }
1767
+
1768
+ function set_border_color($val) {
1769
+ $this->_set_style_type_important('border','_color',$val);
1770
+ }
1771
+
1772
+ function set_border_style($val) {
1773
+ $this->_set_style_type_important('border','_style',$val);
1774
+ }
1775
+
1776
+ /**#@+
1777
+ * Sets the outline styles
1778
+ *
1779
+ * @link http://www.w3.org/TR/CSS21/ui.html#dynamic-outlines
1780
+ * @param string $val
1781
+ */
1782
+ function set_outline($val) {
1783
+ $important = isset($this->_important_props["outline"]);
1784
+
1785
+ $props = array(
1786
+ "outline_style",
1787
+ "outline_width",
1788
+ "outline_color",
1789
+ );
1790
+
1791
+ foreach($props as $prop) {
1792
+ $_val = self::$_defaults[$prop];
1793
+
1794
+ if ( !isset($this->_important_props[$prop]) || $important) {
1795
+ //see __set and __get, on all assignments clear cache!
1796
+ $this->_prop_cache[$prop] = null;
1797
+ if ($important) {
1798
+ $this->_important_props[$prop] = true;
1799
+ }
1800
+ $this->_props[$prop] = $_val;
1801
+ }
1802
+ }
1803
+
1804
+ $val = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces
1805
+ $arr = explode(" ", $val);
1806
+ foreach ($arr as $value) {
1807
+ $value = trim($value);
1808
+ if ( in_array($value, self::$BORDER_STYLES) ) {
1809
+ $this->set_outline_style($value);
1810
+ } else if ( preg_match("/[.0-9]+(?:px|pt|pc|em|ex|%|in|mm|cm)|(?:thin|medium|thick)/", $value ) ) {
1811
+ $this->set_outline_width($value);
1812
+ } else {
1813
+ // must be colour
1814
+ $this->set_outline_color($value);
1815
+ }
1816
+ }
1817
+
1818
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1819
+ $this->_prop_cache["outline"] = null;
1820
+ $this->_props["outline"] = $val;
1821
+ }
1822
+
1823
+ function set_outline_width($val) {
1824
+ $this->_set_style_type_important('outline','_width',$val);
1825
+ }
1826
+
1827
+ function set_outline_color($val) {
1828
+ $this->_set_style_type_important('outline','_color',$val);
1829
+ }
1830
+
1831
+ function set_outline_style($val) {
1832
+ $this->_set_style_type_important('outline','_style',$val);
1833
+ }
1834
+ /**#@-*/
1835
+
1836
+
1837
+ /**
1838
+ * Sets the border spacing
1839
+ *
1840
+ * @link http://www.w3.org/TR/CSS21/box.html#border-properties
1841
+ * @param float $val
1842
+ */
1843
+ function set_border_spacing($val) {
1844
+ $arr = explode(" ", $val);
1845
+
1846
+ if ( count($arr) == 1 )
1847
+ $arr[1] = $arr[0];
1848
+
1849
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1850
+ $this->_prop_cache["border_spacing"] = null;
1851
+ $this->_props["border_spacing"] = "$arr[0] $arr[1]";
1852
+ }
1853
+
1854
+ /**
1855
+ * Sets the list style image
1856
+ *
1857
+ * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-image
1858
+ * @param $val
1859
+ */
1860
+ function set_list_style_image($val) {
1861
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1862
+ $this->_prop_cache["list_style_image"] = null;
1863
+ $this->_props["list_style_image"] = $this->_image($val);
1864
+ }
1865
+
1866
+ /**
1867
+ * Sets the list style
1868
+ *
1869
+ * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style
1870
+ * @param $val
1871
+ */
1872
+ function set_list_style($val) {
1873
+ $important = isset($this->_important_props["list_style"]);
1874
+ $arr = explode(" ", str_replace(",", " ", $val));
1875
+
1876
+ static $types = array(
1877
+ "disc", "circle", "square",
1878
+ "decimal-leading-zero", "decimal", "1",
1879
+ "lower-roman", "upper-roman", "a", "A",
1880
+ "lower-greek",
1881
+ "lower-latin", "upper-latin",
1882
+ "lower-alpha", "upper-alpha",
1883
+ "armenian", "georgian", "hebrew",
1884
+ "cjk-ideographic", "hiragana", "katakana",
1885
+ "hiragana-iroha", "katakana-iroha", "none"
1886
+ );
1887
+
1888
+ static $positions = array("inside", "outside");
1889
+
1890
+ foreach ($arr as $value) {
1891
+ /* http://www.w3.org/TR/CSS21/generate.html#list-style
1892
+ * A value of 'none' for the 'list-style' property sets both 'list-style-type' and 'list-style-image' to 'none'
1893
+ */
1894
+ if ($value === "none") {
1895
+ $this->_set_style("list_style_type", $value, $important);
1896
+ $this->_set_style("list_style_image", $value, $important);
1897
+ continue;
1898
+ }
1899
+
1900
+ //On setting or merging or inheriting list_style_image as well as list_style_type,
1901
+ //and url exists, then url has precedence, otherwise fall back to list_style_type
1902
+ //Firefox is wrong here (list_style_image gets overwritten on explicite list_style_type)
1903
+ //Internet Explorer 7/8 and dompdf is right.
1904
+
1905
+ if (mb_substr($value, 0, 3) === "url") {
1906
+ $this->_set_style("list_style_image", $this->_image($value), $important);
1907
+ continue;
1908
+ }
1909
+
1910
+ if ( in_array($value, $types) ) {
1911
+ $this->_set_style("list_style_type", $value, $important);
1912
+ } else if ( in_array($value, $positions) ) {
1913
+ $this->_set_style("list_style_position", $value, $important);
1914
+ }
1915
+ }
1916
+
1917
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
1918
+ $this->_prop_cache["list_style"] = null;
1919
+ $this->_props["list_style"] = $val;
1920
+ }
1921
+
1922
+ function set_size($val) {
1923
+ $length_re = "/(\d+\s*(?:pt|px|pc|em|ex|in|cm|mm|%))/";
1924
+
1925
+ $val = mb_strtolower($val);
1926
+
1927
+ if ( $val === "auto" ) {
1928
+ return;
1929
+ }
1930
+
1931
+ $parts = preg_split("/\s+/", $val);
1932
+
1933
+ $computed = array();
1934
+ if ( preg_match($length_re, $parts[0]) ) {
1935
+ $computed[] = $this->length_in_pt($parts[0]);
1936
+
1937
+ if ( isset($parts[1]) && preg_match($length_re, $parts[1]) ) {
1938
+ $computed[] = $this->length_in_pt($parts[1]);
1939
+ }
1940
+ else {
1941
+ $computed[] = $computed[0];
1942
+ }
1943
+ }
1944
+ elseif ( isset(CPDF_Adapter::$PAPER_SIZES[$parts[0]]) ) {
1945
+ $computed = array_slice(CPDF_Adapter::$PAPER_SIZES[$parts[0]], 2, 2);
1946
+
1947
+ if ( isset($parts[1]) && $parts[1] === "landscape" ) {
1948
+ $computed = array_reverse($computed);
1949
+ }
1950
+ }
1951
+ else {
1952
+ return;
1953
+ }
1954
+
1955
+ $this->_props["size"] = $computed;
1956
+ }
1957
+
1958
+ /**
1959
+ * Sets the CSS3 transform property
1960
+ *
1961
+ * @link http://www.w3.org/TR/css3-2d-transforms/#transform-property
1962
+ * @param string $val
1963
+ */
1964
+ function set_transform($val) {
1965
+ $number = "\s*([^,\s]+)\s*";
1966
+ $tr_value = "\s*([^,\s]+)\s*";
1967
+ $angle = "\s*([^,\s]+(?:deg|rad)?)\s*";
1968
+
1969
+ if( !preg_match_all("/[a-z]+\([^\)]+\)/i", $val, $parts, PREG_SET_ORDER) ) {
1970
+ return;
1971
+ }
1972
+
1973
+ $functions = array(
1974
+ //"matrix" => "\($number,$number,$number,$number,$number,$number\)",
1975
+
1976
+ "translate" => "\($tr_value(?:,$tr_value)?\)",
1977
+ "translateX" => "\($tr_value\)",
1978
+ "translateY" => "\($tr_value\)",
1979
+
1980
+ "scale" => "\($number(?:,$number)?\)",
1981
+ "scaleX" => "\($number\)",
1982
+ "scaleY" => "\($number\)",
1983
+
1984
+ "rotate" => "\($angle\)",
1985
+
1986
+ "skew" => "\($angle(?:,$angle)?\)",
1987
+ "skewX" => "\($angle\)",
1988
+ "skewY" => "\($angle\)",
1989
+ );
1990
+
1991
+ $transforms = array();
1992
+
1993
+ foreach($parts as $part) {
1994
+ $t = $part[0];
1995
+
1996
+ foreach($functions as $name => $pattern) {
1997
+ if (preg_match("/$name\s*$pattern/i", $t, $matches)) {
1998
+ $values = array_slice($matches, 1);
1999
+
2000
+ switch($name) {
2001
+ // <angle> units
2002
+ case "rotate":
2003
+ case "skew":
2004
+ case "skewX":
2005
+ case "skewY":
2006
+
2007
+ foreach($values as $i => $value) {
2008
+ if ( strpos($value, "rad") )
2009
+ $values[$i] = rad2deg(floatval($value));
2010
+ else
2011
+ $values[$i] = floatval($value);
2012
+ }
2013
+
2014
+ switch($name) {
2015
+ case "skew":
2016
+ if ( !isset($values[1]) )
2017
+ $values[1] = 0;
2018
+ break;
2019
+ case "skewX":
2020
+ $name = "skew";
2021
+ $values = array($values[0], 0);
2022
+ break;
2023
+ case "skewY":
2024
+ $name = "skew";
2025
+ $values = array(0, $values[0]);
2026
+ break;
2027
+ }
2028
+ break;
2029
+
2030
+ // <translation-value> units
2031
+ case "translate":
2032
+ $values[0] = $this->length_in_pt($values[0], $this->width);
2033
+
2034
+ if ( isset($values[1]) )
2035
+ $values[1] = $this->length_in_pt($values[1], $this->height);
2036
+ else
2037
+ $values[1] = 0;
2038
+ break;
2039
+
2040
+ case "translateX":
2041
+ $name = "translate";
2042
+ $values = array($this->length_in_pt($values[0], $this->width), 0);
2043
+ break;
2044
+
2045
+ case "translateY":
2046
+ $name = "translate";
2047
+ $values = array(0, $this->length_in_pt($values[0], $this->height));
2048
+ break;
2049
+
2050
+ // <number> units
2051
+ case "scale":
2052
+ if ( !isset($values[1]) )
2053
+ $values[1] = $values[0];
2054
+ break;
2055
+
2056
+ case "scaleX":
2057
+ $name = "scale";
2058
+ $values = array($values[0], 1.0);
2059
+ break;
2060
+
2061
+ case "scaleY":
2062
+ $name = "scale";
2063
+ $values = array(1.0, $values[0]);
2064
+ break;
2065
+ }
2066
+
2067
+ $transforms[] = array(
2068
+ $name,
2069
+ $values,
2070
+ );
2071
+ }
2072
+ }
2073
+ }
2074
+
2075
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
2076
+ $this->_prop_cache["transform"] = null;
2077
+ $this->_props["transform"] = $transforms;
2078
+ }
2079
+
2080
+ function set__webkit_transform($val) {
2081
+ return $this->set_transform($val);
2082
+ }
2083
+
2084
+ function set__webkit_transform_origin($val) {
2085
+ return $this->set_transform_origin($val);
2086
+ }
2087
+
2088
+ /**
2089
+ * Sets the CSS3 transform-origin property
2090
+ *
2091
+ * @link http://www.w3.org/TR/css3-2d-transforms/#transform-origin
2092
+ * @param string $val
2093
+ */
2094
+ function set_transform_origin($val) {
2095
+ $values = preg_split("/\s+/", $val);
2096
+
2097
+ if ( count($values) === 0) {
2098
+ return;
2099
+ }
2100
+
2101
+ foreach($values as &$value) {
2102
+ if ( in_array($value, array("top", "left")) ) {
2103
+ $value = 0;
2104
+ }
2105
+
2106
+ if ( in_array($value, array("bottom", "right")) ) {
2107
+ $value = "100%";
2108
+ }
2109
+ }
2110
+
2111
+ if ( !isset($values[1]) ) {
2112
+ $values[1] = $values[0];
2113
+ }
2114
+
2115
+ //see __set and __get, on all assignments clear cache, not needed on direct set through __set
2116
+ $this->_prop_cache["transform_origin"] = null;
2117
+ $this->_props["transform_origin"] = $values;
2118
+ }
2119
+
2120
+ protected function parse_image_resolution($val) {
2121
+ // If exif data could be get:
2122
+ // $re = '/^\s*(\d+|normal|auto)(?:\s*,\s*(\d+|normal))?\s*$/';
2123
+
2124
+ $re = '/^\s*(\d+|normal|auto)\s*$/';
2125
+
2126
+ if ( !preg_match($re, $val, $matches) ) {
2127
+ return null;
2128
+ }
2129
+
2130
+ return $matches[1];
2131
+ }
2132
+
2133
+ // auto | normal | dpi
2134
+ function set_background_image_resolution($val) {
2135
+ $parsed = $this->parse_image_resolution($val);
2136
+
2137
+ $this->_prop_cache["background_image_resolution"] = null;
2138
+ $this->_props["background_image_resolution"] = $parsed;
2139
+ }
2140
+
2141
+ // auto | normal | dpi
2142
+ function set_image_resolution($val) {
2143
+ $parsed = $this->parse_image_resolution($val);
2144
+
2145
+ $this->_prop_cache["image_resolution"] = null;
2146
+ $this->_props["image_resolution"] = $parsed;
2147
+ }
2148
+
2149
+ function set__dompdf_background_image_resolution($val) {
2150
+ return $this->set_background_image_resolution($val);
2151
+ }
2152
+
2153
+ function set__dompdf_image_resolution($val) {
2154
+ return $this->set_image_resolution($val);
2155
+ }
2156
+
2157
+ function set_z_index($val) {
2158
+ if ( round($val) != $val && $val !== "auto" ) {
2159
+ return;
2160
+ }
2161
+
2162
+ $this->_prop_cache["z_index"] = null;
2163
+ $this->_props["z_index"] = $val;
2164
+ }
2165
+
2166
+ function set_counter_increment($val) {
2167
+ $val = trim($val);
2168
+ $value = null;
2169
+
2170
+ if ( in_array($val, array("none", "inherit")) ) {
2171
+ $value = $val;
2172
+ }
2173
+ else {
2174
+ if ( preg_match_all("/(".self::CSS_IDENTIFIER.")(?:\s+(".self::CSS_INTEGER."))?/", $val, $matches, PREG_SET_ORDER) ){
2175
+ $value = array();
2176
+ foreach($matches as $match) {
2177
+ $value[$match[1]] = isset($match[2]) ? $match[2] : 1;
2178
+ }
2179
+ }
2180
+ }
2181
+
2182
+ $this->_prop_cache["counter_increment"] = null;
2183
+ $this->_props["counter_increment"] = $value;
2184
+ }
2185
+
2186
+ /**
2187
+ * Generate a string representation of the Style
2188
+ *
2189
+ * This dumps the entire property array into a string via print_r. Useful
2190
+ * for debugging.
2191
+ *
2192
+ * @return string
2193
+ */
2194
+ /*DEBUGCSS print: see below additional debugging util*/
2195
+ function __toString() {
2196
+ return print_r(array_merge(array("parent_font_size" => $this->_parent_font_size),
2197
+ $this->_props), true);
2198
+ }
2199
+
2200
+ /*DEBUGCSS*/ function debug_print()
2201
+ /*DEBUGCSS*/ {
2202
+ /*DEBUGCSS*/ print "parent_font_size:".$this->_parent_font_size . ";\n";
2203
+ /*DEBUGCSS*/ foreach($this->_props as $prop => $val ) {
2204
+ /*DEBUGCSS*/ print $prop.':'.$val;
2205
+ /*DEBUGCSS*/ if (isset($this->_important_props[$prop])) {
2206
+ /*DEBUGCSS*/ print '!important';
2207
+ /*DEBUGCSS*/ }
2208
+ /*DEBUGCSS*/ print ";\n";
2209
+ /*DEBUGCSS*/ }
2210
+ /*DEBUGCSS*/ }
2211
+ }
dompdf/include/stylesheet.cls.php ADDED
@@ -0,0 +1,1362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: stylesheet.cls.php 461 2012-01-26 20:26:02Z fabien.menager $
10
+ */
11
+
12
+ /**
13
+ * The location of the default built-in CSS file.
14
+ * {@link Stylesheet::DEFAULT_STYLESHEET}
15
+ */
16
+ define('__DEFAULT_STYLESHEET', DOMPDF_LIB_DIR . DIRECTORY_SEPARATOR . "res" . DIRECTORY_SEPARATOR . "html.css");
17
+
18
+ /**
19
+ * The master stylesheet class
20
+ *
21
+ * The Stylesheet class is responsible for parsing stylesheets and style
22
+ * tags/attributes. It also acts as a registry of the individual Style
23
+ * objects generated by the current set of loaded CSS files and style
24
+ * elements.
25
+ *
26
+ * @see Style
27
+ * @package dompdf
28
+ */
29
+ class Stylesheet {
30
+
31
+ /**
32
+ * The location of the default built-in CSS file.
33
+ */
34
+ const DEFAULT_STYLESHEET = __DEFAULT_STYLESHEET;
35
+
36
+ /**
37
+ * User agent stylesheet origin
38
+ * @var int
39
+ */
40
+ const ORIG_UA = 1;
41
+
42
+ /**
43
+ * User normal stylesheet origin
44
+ * @var int
45
+ */
46
+ const ORIG_USER = 2;
47
+
48
+ /**
49
+ * Author normal stylesheet origin
50
+ * @var int
51
+ */
52
+ const ORIG_AUTHOR = 3;
53
+
54
+ private static $_stylesheet_origins = array(
55
+ self::ORIG_UA => -0x0FFFFFFF, // user agent style sheets
56
+ self::ORIG_USER => -0x0000FFFF, // user normal style sheets
57
+ self::ORIG_AUTHOR => 0x00000000, // author normal style sheets
58
+ );
59
+
60
+ /**
61
+ * Current dompdf instance
62
+ * @var DOMPDF
63
+ */
64
+ private $_dompdf;
65
+
66
+ /**
67
+ * Array of currently defined styles
68
+ * @var array
69
+ */
70
+ private $_styles;
71
+
72
+ /**
73
+ * Base protocol of the document being parsed
74
+ * Used to handle relative urls.
75
+ * @var string
76
+ */
77
+ private $_protocol;
78
+
79
+ /**
80
+ * Base hostname of the document being parsed
81
+ * Used to handle relative urls.
82
+ * @var string
83
+ */
84
+ private $_base_host;
85
+
86
+ /**
87
+ * Base path of the document being parsed
88
+ * Used to handle relative urls.
89
+ * @var string
90
+ */
91
+ private $_base_path;
92
+
93
+ /**
94
+ * The styles defined by @page rules
95
+ * @var array<Style>
96
+ */
97
+ private $_page_styles;
98
+
99
+ /**
100
+ * List of loaded files, used to prevent recursion
101
+ * @var array
102
+ */
103
+ private $_loaded_files;
104
+
105
+ private $_current_origin = self::ORIG_UA;
106
+
107
+ /**
108
+ * Accepted CSS media types
109
+ * List of types and parsing rules for future extensions:
110
+ * http://www.w3.org/TR/REC-html40/types.html
111
+ * screen, tty, tv, projection, handheld, print, braille, aural, all
112
+ * The following are non standard extensions for undocumented specific environments.
113
+ * static, visual, bitmap, paged, dompdf
114
+ * Note, even though the generated pdf file is intended for print output,
115
+ * the desired content might be different (e.g. screen or projection view of html file).
116
+ * Therefore allow specification of content by dompdf setting DOMPDF_DEFAULT_MEDIA_TYPE.
117
+ * If given, replace media "print" by DOMPDF_DEFAULT_MEDIA_TYPE.
118
+ * (Previous version $ACCEPTED_MEDIA_TYPES = $ACCEPTED_GENERIC_MEDIA_TYPES + $ACCEPTED_DEFAULT_MEDIA_TYPE)
119
+ */
120
+ static $ACCEPTED_DEFAULT_MEDIA_TYPE = "print";
121
+ static $ACCEPTED_GENERIC_MEDIA_TYPES = array("all", "static", "visual", "bitmap", "paged", "dompdf");
122
+
123
+ /**
124
+ * The class constructor.
125
+ *
126
+ * The base protocol, host & path are initialized to those of
127
+ * the current script.
128
+ */
129
+ function __construct(DOMPDF $dompdf) {
130
+ $this->_dompdf = $dompdf;
131
+ $this->_styles = array();
132
+ $this->_loaded_files = array();
133
+ list($this->_protocol, $this->_base_host, $this->_base_path) = explode_url($_SERVER["SCRIPT_FILENAME"]);
134
+ $this->_page_styles = array("base" => null);
135
+ }
136
+
137
+ /**
138
+ * Class destructor
139
+ */
140
+ function __destruct() {
141
+ clear_object($this);
142
+ }
143
+
144
+ /**
145
+ * Set the base protocol
146
+ *
147
+ * @param string $proto
148
+ */
149
+ function set_protocol($proto) { $this->_protocol = $proto; }
150
+
151
+ /**
152
+ * Set the base host
153
+ *
154
+ * @param string $host
155
+ */
156
+ function set_host($host) { $this->_base_host = $host; }
157
+
158
+ /**
159
+ * Set the base path
160
+ *
161
+ * @param string $path
162
+ */
163
+ function set_base_path($path) { $this->_base_path = $path; }
164
+
165
+ /**
166
+ * Return the DOMPDF object
167
+ *
168
+ * @return DOMPDF
169
+ */
170
+ function get_dompdf() { return $this->_dompdf; }
171
+
172
+ /**
173
+ * Return the base protocol for this stylesheet
174
+ *
175
+ * @return string
176
+ */
177
+ function get_protocol() { return $this->_protocol; }
178
+
179
+ /**
180
+ * Return the base host for this stylesheet
181
+ *
182
+ * @return string
183
+ */
184
+ function get_host() { return $this->_base_host; }
185
+
186
+ /**
187
+ * Return the base path for this stylesheet
188
+ *
189
+ * @return string
190
+ */
191
+ function get_base_path() { return $this->_base_path; }
192
+
193
+ /**
194
+ * Return the array of page styles
195
+ *
196
+ * @return array<Style>
197
+ */
198
+ function get_page_styles() { return $this->_page_styles; }
199
+
200
+ /**
201
+ * Add a new Style object to the stylesheet
202
+ *
203
+ * add_style() adds a new Style object to the current stylesheet, or
204
+ * merges a new Style with an existing one.
205
+ *
206
+ * @param string $key the Style's selector
207
+ * @param Style $style the Style to be added
208
+ */
209
+ function add_style($key, Style $style) {
210
+ if (!is_string($key))
211
+ throw new DOMPDF_Exception("CSS rule must be keyed by a string.");
212
+
213
+ if ( isset($this->_styles[$key]) )
214
+ $this->_styles[$key]->merge($style);
215
+ else
216
+ $this->_styles[$key] = clone $style;
217
+
218
+ $this->_styles[$key]->set_origin( $this->_current_origin );
219
+ }
220
+
221
+ /**
222
+ * lookup a specifc Style object
223
+ *
224
+ * lookup() returns the Style specified by $key, or null if the Style is
225
+ * not found.
226
+ *
227
+ * @param string $key the selector of the requested Style
228
+ * @return Style
229
+ */
230
+ function lookup($key) {
231
+ if ( !isset($this->_styles[$key]) )
232
+ return null;
233
+
234
+ return $this->_styles[$key];
235
+ }
236
+
237
+ /**
238
+ * create a new Style object associated with this stylesheet
239
+ *
240
+ * @param Style $parent The style of this style's parent in the DOM tree
241
+ * @return Style
242
+ */
243
+ function create_style(Style $parent = null) {
244
+ return new Style($this, $this->_current_origin);
245
+ }
246
+
247
+ /**
248
+ * load and parse a CSS string
249
+ *
250
+ * @param string $css
251
+ */
252
+ function load_css(&$css) { $this->_parse_css($css); }
253
+
254
+
255
+ /**
256
+ * load and parse a CSS file
257
+ *
258
+ * @param string $file
259
+ */
260
+ function load_css_file($file, $origin = self::ORIG_AUTHOR) {
261
+ global $_dompdf_warnings;
262
+
263
+ if ( $origin ) {
264
+ $this->_current_origin = $origin;
265
+ }
266
+
267
+ // Prevent circular references
268
+ if ( isset($this->_loaded_files[$file]) )
269
+ return;
270
+
271
+ $this->_loaded_files[$file] = true;
272
+ $parsed_url = explode_url($file);
273
+
274
+ list($this->_protocol, $this->_base_host, $this->_base_path, $filename) = $parsed_url;
275
+
276
+ // Fix submitted by Nick Oostveen for aliased directory support:
277
+ if ( $this->_protocol == "" )
278
+ $file = $this->_base_path . $filename;
279
+ else
280
+ $file = build_url($this->_protocol, $this->_base_host, $this->_base_path, $filename);
281
+
282
+ set_error_handler("record_warnings");
283
+ $css = file_get_contents($file, null, $this->_dompdf->get_http_context());
284
+
285
+ $good_mime_type = true;
286
+
287
+ if ( !$this->_dompdf->get_quirksmode() ) {
288
+ // See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
289
+ if ( isset($http_response_header) ) {
290
+ foreach($http_response_header as $_header) {
291
+ if ( preg_match("@Content-Type:\s*([\w/]+)@i", $_header, $matches) ) {
292
+ if ( $matches[1] !== "text/css" ) {
293
+ $good_mime_type = false;
294
+ }
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ restore_error_handler();
301
+
302
+ if ( !$good_mime_type || $css == "" ) {
303
+ record_warnings(E_USER_WARNING, "Unable to load css file $file", __FILE__, __LINE__);
304
+ return;
305
+ }
306
+
307
+ $this->_parse_css($css);
308
+ }
309
+
310
+ /**
311
+ * @link http://www.w3.org/TR/CSS21/cascade.html#specificity
312
+ *
313
+ *
314
+ *
315
+ * @param string $selector
316
+ * @param string $origin :
317
+ * - ua: user agent style sheets
318
+ * - un: user normal style sheets
319
+ * - an: author normal style sheets
320
+ * - ai: author important style sheets
321
+ * - ui: user important style sheets
322
+ *
323
+ * @return int
324
+ */
325
+ private function _specificity($selector, $origin = self::ORIG_AUTHOR) {
326
+ // http://www.w3.org/TR/CSS21/cascade.html#specificity
327
+ // ignoring the ":" pseudoclass modifyers
328
+ // also ignored in _css_selector_to_xpath
329
+
330
+ $a = ($selector === "!attr") ? 1 : 0;
331
+
332
+ $b = min(mb_substr_count($selector, "#"), 255);
333
+
334
+ $c = min(mb_substr_count($selector, ".") +
335
+ mb_substr_count($selector, "["), 255);
336
+
337
+ $d = min(mb_substr_count($selector, " ") +
338
+ mb_substr_count($selector, ">") +
339
+ mb_substr_count($selector, "+"), 255);
340
+
341
+ //If a normal element name is at the begining of the string,
342
+ //a leading whitespace might have been removed on whitespace collapsing and removal
343
+ //therefore there might be one whitespace less as selected element names
344
+ //this can lead to a too small specificity
345
+ //see _css_selector_to_xpath
346
+
347
+ if ( !in_array($selector[0], array(" ", ">", ".", "#", "+", ":", "["))/* && $selector !== "*"*/) {
348
+ $d++;
349
+ }
350
+
351
+ if (DEBUGCSS) {
352
+ /*DEBUGCSS*/ print "<pre>\n";
353
+ /*DEBUGCSS*/ printf("_specificity(): 0x%08x \"%s\"\n", ($a << 24) | ($b << 16) | ($c << 8) | ($d), $selector);
354
+ /*DEBUGCSS*/ print "</pre>";
355
+ }
356
+
357
+ return self::$_stylesheet_origins[$origin] + ($a << 24) | ($b << 16) | ($c << 8) | ($d);
358
+ }
359
+
360
+ /**
361
+ * converts a CSS selector to an XPath query.
362
+ *
363
+ * @param string $selector
364
+ * @return string
365
+ */
366
+ private function _css_selector_to_xpath($selector, $first_pass = false) {
367
+
368
+ // Collapse white space and strip whitespace around delimiters
369
+ // $search = array("/\\s+/", "/\\s+([.>#+:])\\s+/");
370
+ // $replace = array(" ", "\\1");
371
+ // $selector = preg_replace($search, $replace, trim($selector));
372
+
373
+ // Initial query (non-absolute)
374
+ $query = "//";
375
+
376
+ // Will contain :before and :after if they must be created
377
+ $pseudo_elements = array();
378
+
379
+ // Parse the selector
380
+ //$s = preg_split("/([ :>.#+])/", $selector, -1, PREG_SPLIT_DELIM_CAPTURE);
381
+
382
+ $delimiters = array(" ", ">", ".", "#", "+", ":", "[", "(");
383
+
384
+ // Add an implicit * at the beginning of the selector
385
+ // if it begins with an attribute selector
386
+ if ( $selector[0] === "[" )
387
+ $selector = "*$selector";
388
+
389
+ // Add an implicit space at the beginning of the selector if there is no
390
+ // delimiter there already.
391
+ if ( !in_array($selector[0], $delimiters) )
392
+ $selector = " $selector";
393
+
394
+ $tok = "";
395
+ $len = mb_strlen($selector);
396
+ $i = 0;
397
+
398
+ while ( $i < $len ) {
399
+
400
+ $s = $selector[$i];
401
+ $i++;
402
+
403
+ // Eat characters up to the next delimiter
404
+ $tok = "";
405
+ $in_attr = false;
406
+
407
+ while ($i < $len) {
408
+ $c = $selector[$i];
409
+ $c_prev = $selector[$i-1];
410
+
411
+ if ( !$in_attr && in_array($c, $delimiters) )
412
+ break;
413
+
414
+ if ( $c_prev === "[" ) {
415
+ $in_attr = true;
416
+ }
417
+
418
+ $tok .= $selector[$i++];
419
+ }
420
+
421
+ switch ($s) {
422
+
423
+ case " ":
424
+ case ">":
425
+ // All elements matching the next token that are direct children of
426
+ // the current token
427
+ $expr = $s === " " ? "descendant" : "child";
428
+
429
+ if ( mb_substr($query, -1, 1) !== "/" )
430
+ $query .= "/";
431
+
432
+ // Tag names are case-insensitive
433
+ $tok = strtolower($tok);
434
+
435
+ if ( !$tok )
436
+ $tok = "*";
437
+
438
+ $query .= "$expr::$tok";
439
+ $tok = "";
440
+ break;
441
+
442
+ case ".":
443
+ case "#":
444
+ // All elements matching the current token with a class/id equal to
445
+ // the _next_ token.
446
+
447
+ $attr = $s === "." ? "class" : "id";
448
+
449
+ // empty class/id == *
450
+ if ( mb_substr($query, -1, 1) === "/" )
451
+ $query .= "*";
452
+
453
+ // Match multiple classes: $tok contains the current selected
454
+ // class. Search for class attributes with class="$tok",
455
+ // class=".* $tok .*" and class=".* $tok"
456
+
457
+ // This doesn't work because libxml only supports XPath 1.0...
458
+ //$query .= "[matches(@$attr,\"^${tok}\$|^${tok}[ ]+|[ ]+${tok}\$|[ ]+${tok}[ ]+\")]";
459
+
460
+ // Query improvement by Michael Sheakoski <michael@mjsdigital.com>:
461
+ $query .= "[contains(concat(' ', @$attr, ' '), concat(' ', '$tok', ' '))]";
462
+ $tok = "";
463
+ break;
464
+
465
+ case "+":
466
+ // All sibling elements that folow the current token
467
+ if ( mb_substr($query, -1, 1) !== "/" )
468
+ $query .= "/";
469
+
470
+ $query .= "following-sibling::$tok";
471
+ $tok = "";
472
+ break;
473
+
474
+ case ":":
475
+ $i2 = $i-strlen($tok)-2; // the char before ":"
476
+ if ( !isset($selector[$i2]) || in_array($selector[$i2], $delimiters) ) {
477
+ $query .= "*";
478
+ }
479
+
480
+ $last = false;
481
+
482
+ // Pseudo-classes
483
+ switch ($tok) {
484
+
485
+ case "first-child":
486
+ $query .= "[1]";
487
+ $tok = "";
488
+ break;
489
+
490
+ case "last-child":
491
+ $query .= "[not(following-sibling::*)]";
492
+ $tok = "";
493
+ break;
494
+
495
+ case "first-of-type":
496
+ $query .= "[position() = 1]";
497
+ $tok = "";
498
+ break;
499
+
500
+ case "last-of-type":
501
+ $query .= "[position() = last()]";
502
+ $tok = "";
503
+ break;
504
+
505
+ // an+b, n, odd, and even
506
+ case "nth-last-of-type":
507
+ case "nth-last-child":
508
+ $last = true;
509
+
510
+ case "nth-of-type":
511
+ case "nth-child":
512
+ $p = $i+1;
513
+ $nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i)-$p));
514
+
515
+ $condition = "";
516
+
517
+ // 1
518
+ if ( preg_match("/^\d+$/", $nth) ) {
519
+ $condition = "position() = $nth";
520
+ }
521
+
522
+ // odd
523
+ elseif ( $nth === "odd" ) {
524
+ $condition = "(position() mod 2) = 1";
525
+ }
526
+
527
+ // even
528
+ elseif ( $nth === "even" ) {
529
+ $condition = "(position() mod 2) = 0";
530
+ }
531
+
532
+ // an+b
533
+ else {
534
+ $condition = $this->_selector_an_plus_b($nth, $last);
535
+ }
536
+
537
+ $query .= "[$condition]";
538
+ $tok = "";
539
+ break;
540
+
541
+ case "link":
542
+ $query .= "[@href]";
543
+ $tok = "";
544
+ break;
545
+
546
+ case "first-line": // TODO
547
+ case "first-letter": // TODO
548
+
549
+ // N/A
550
+ case "active":
551
+ case "hover":
552
+ case "visited":
553
+ $query .= "[false()]";
554
+ $tok = "";
555
+ break;
556
+
557
+ /* Pseudo-elements */
558
+ case "before":
559
+ case "after":
560
+ if ( $first_pass )
561
+ $pseudo_elements[$tok] = $tok;
562
+ else
563
+ $query .= "/*[@$tok]";
564
+
565
+ $tok = "";
566
+ break;
567
+
568
+ case "empty":
569
+ $query .= "[not(*) and not(normalize-space())]";
570
+ $tok = "";
571
+ break;
572
+
573
+ case "disabled":
574
+ case "checked":
575
+ $query .= "[@$tok]";
576
+ $tok = "";
577
+ break;
578
+
579
+ case "enabled":
580
+ $query .= "[not(@disabled)]";
581
+ $tok = "";
582
+ break;
583
+ }
584
+
585
+ break;
586
+
587
+ case "[":
588
+ // Attribute selectors. All with an attribute matching the following token(s)
589
+ $attr_delimiters = array("=", "]", "~", "|", "$", "^", "*");
590
+ $tok_len = mb_strlen($tok);
591
+ $j = 0;
592
+
593
+ $attr = "";
594
+ $op = "";
595
+ $value = "";
596
+
597
+ while ( $j < $tok_len ) {
598
+ if ( in_array($tok[$j], $attr_delimiters) )
599
+ break;
600
+ $attr .= $tok[$j++];
601
+ }
602
+
603
+ switch ( $tok[$j] ) {
604
+
605
+ case "~":
606
+ case "|":
607
+ case "$":
608
+ case "^":
609
+ case "*":
610
+ $op .= $tok[$j++];
611
+
612
+ if ( $tok[$j] !== "=" )
613
+ throw new DOMPDF_Exception("Invalid CSS selector syntax: invalid attribute selector: $selector");
614
+
615
+ $op .= $tok[$j];
616
+ break;
617
+
618
+ case "=":
619
+ $op = "=";
620
+ break;
621
+
622
+ }
623
+
624
+ // Read the attribute value, if required
625
+ if ( $op != "" ) {
626
+ $j++;
627
+ while ( $j < $tok_len ) {
628
+ if ( $tok[$j] === "]" )
629
+ break;
630
+ $value .= $tok[$j++];
631
+ }
632
+ }
633
+
634
+ if ( $attr == "" )
635
+ throw new DOMPDF_Exception("Invalid CSS selector syntax: missing attribute name");
636
+
637
+ $value = trim($value, "\"'");
638
+
639
+ switch ( $op ) {
640
+
641
+ case "":
642
+ $query .= "[@$attr]";
643
+ break;
644
+
645
+ case "=":
646
+ $query .= "[@$attr=\"$value\"]";
647
+ break;
648
+
649
+ case "~=":
650
+ // FIXME: this will break if $value contains quoted strings
651
+ // (e.g. [type~="a b c" "d e f"])
652
+ $values = explode(" ", $value);
653
+ $query .= "[";
654
+
655
+ foreach ( $values as $val )
656
+ $query .= "@$attr=\"$val\" or ";
657
+
658
+ $query = rtrim($query, " or ") . "]";
659
+ break;
660
+
661
+ case "|=":
662
+ $values = explode("-", $value);
663
+ $query .= "[";
664
+
665
+ foreach ( $values as $val )
666
+ $query .= "starts-with(@$attr, \"$val\") or ";
667
+
668
+ $query = rtrim($query, " or ") . "]";
669
+ break;
670
+
671
+ case "$=":
672
+ $query .= "[substring(@$attr, string-length(@$attr)-".(strlen($value) - 1).")=\"$value\"]";
673
+ break;
674
+
675
+ case "^=":
676
+ $query .= "[starts-with(@$attr,\"$value\")]";
677
+ break;
678
+
679
+ case "*=":
680
+ $query .= "[contains(@$attr,\"$value\")]";
681
+ break;
682
+ }
683
+
684
+ break;
685
+ }
686
+ }
687
+ $i++;
688
+
689
+ // case ":":
690
+ // // Pseudo selectors: ignore for now. Partially handled directly
691
+ // // below.
692
+
693
+ // // Skip until the next special character, leaving the token as-is
694
+ // while ( $i < $len ) {
695
+ // if ( in_array($selector[$i], $delimiters) )
696
+ // break;
697
+ // $i++;
698
+ // }
699
+ // break;
700
+
701
+ // default:
702
+ // // Add the character to the token
703
+ // $tok .= $selector[$i++];
704
+ // break;
705
+ // }
706
+
707
+ // }
708
+
709
+
710
+ // Trim the trailing '/' from the query
711
+ if ( mb_strlen($query) > 2 )
712
+ $query = rtrim($query, "/");
713
+
714
+ return array("query" => $query, "pseudo_elements" => $pseudo_elements);
715
+ }
716
+
717
+ // https://github.com/tenderlove/nokogiri/blob/master/lib/nokogiri/css/xpath_visitor.rb
718
+ protected function _selector_an_plus_b($expr, $last = false) {
719
+ $expr = preg_replace("/\s/", "", $expr);
720
+ if ( !preg_match("/^(?P<a>-?[0-9]*)?n(?P<b>[-+]?[0-9]+)?$/", $expr, $matches)) {
721
+ return "false()";
722
+ }
723
+
724
+ $a = ((isset($matches["a"]) && $matches["a"] !== "") ? intval($matches["a"]) : 1);
725
+ $b = ((isset($matches["b"]) && $matches["b"] !== "") ? intval($matches["b"]) : 0);
726
+
727
+ $position = ($last ? "(last()-position()+1)" : "position()");
728
+
729
+ if ($b == 0) {
730
+ return "($position mod $a) = 0";
731
+ }
732
+ else {
733
+ $compare = (($a < 0) ? "<=" : ">=");
734
+ $b2 = -$b;
735
+ if( $b2 >= 0 ) {
736
+ $b2 = "+$b2";
737
+ }
738
+ return "($position $compare $b) and ((($position $b2) mod ".abs($a).") = 0)";
739
+ }
740
+ }
741
+
742
+ /**
743
+ * applies all current styles to a particular document tree
744
+ *
745
+ * apply_styles() applies all currently loaded styles to the provided
746
+ * {@link Frame_Tree}. Aside from parsing CSS, this is the main purpose
747
+ * of this class.
748
+ *
749
+ * @param Frame_Tree $tree
750
+ */
751
+ function apply_styles(Frame_Tree $tree) {
752
+ // Use XPath to select nodes. This would be easier if we could attach
753
+ // Frame objects directly to DOMNodes using the setUserData() method, but
754
+ // we can't do that just yet. Instead, we set a _node attribute_ in
755
+ // Frame->set_id() and use that as a handle on the Frame object via
756
+ // Frame_Tree::$_registry.
757
+
758
+ // We create a scratch array of styles indexed by frame id. Once all
759
+ // styles have been assigned, we order the cached styles by specificity
760
+ // and create a final style object to assign to the frame.
761
+
762
+ // FIXME: this is not particularly robust...
763
+
764
+ $styles = array();
765
+ $xp = new DOMXPath($tree->get_dom());
766
+
767
+ // Add generated content
768
+ foreach ($this->_styles as $selector => $style) {
769
+ if (strpos($selector, ":before") === false &&
770
+ strpos($selector, ":after") === false) continue;
771
+
772
+ $query = $this->_css_selector_to_xpath($selector, true);
773
+
774
+ // Retrieve the nodes
775
+ $nodes = @$xp->query($query["query"]);
776
+ if ($nodes == null) {
777
+ record_warnings(E_USER_WARNING, "The CSS selector '$selector' is not valid", __FILE__, __LINE__);
778
+ continue;
779
+ }
780
+
781
+ foreach ($nodes as $i => $node) {
782
+ foreach ($query["pseudo_elements"] as $pos) {
783
+ // Do not add a new pseudo element if another one already matched
784
+ if ( $node->hasAttribute("dompdf_{$pos}_frame_id") ) {
785
+ continue;
786
+ }
787
+
788
+ if (($src = $this->_image($style->content)) !== "none") {
789
+ $new_node = $node->ownerDocument->createElement("img_generated");
790
+ $new_node->setAttribute("src", $src);
791
+ }
792
+ else {
793
+ $new_node = $node->ownerDocument->createElement("dompdf_generated");
794
+ }
795
+
796
+ $new_node->setAttribute($pos, $pos);
797
+
798
+ $new_frame_id = $tree->insert_node($node, $new_node, $pos);
799
+
800
+ $node->setAttribute("dompdf_{$pos}_frame_id", $new_frame_id);
801
+ }
802
+ }
803
+ }
804
+
805
+ // Apply all styles in stylesheet
806
+ foreach ($this->_styles as $selector => $style) {
807
+ $query = $this->_css_selector_to_xpath($selector);
808
+
809
+ // Retrieve the nodes
810
+ $nodes = @$xp->query($query["query"]);
811
+ if ($nodes == null) {
812
+ record_warnings(E_USER_WARNING, "The CSS selector '$selector' is not valid", __FILE__, __LINE__);
813
+ continue;
814
+ }
815
+
816
+ foreach ($nodes as $node) {
817
+ // Retrieve the node id
818
+ if ( $node->nodeType != XML_ELEMENT_NODE ) // Only DOMElements get styles
819
+ continue;
820
+
821
+ $id = $node->getAttribute("frame_id");
822
+
823
+ // Assign the current style to the scratch array
824
+ $spec = $this->_specificity($selector);
825
+ $styles[$id][$spec][] = $style;
826
+ }
827
+ }
828
+
829
+ // Now create the styles and assign them to the appropriate frames. (We
830
+ // iterate over the tree using an implicit Frame_Tree iterator.)
831
+ $root_flg = false;
832
+ foreach ($tree->get_frames() as $frame) {
833
+ // pre_r($frame->get_node()->nodeName . ":");
834
+ if ( !$root_flg && $this->_page_styles["base"] ) {
835
+ $style = $this->_page_styles["base"];
836
+ $root_flg = true;
837
+ } else
838
+ $style = $this->create_style();
839
+
840
+ // Find nearest DOMElement parent
841
+ $p = $frame;
842
+ while ( $p = $p->get_parent() )
843
+ if ($p->get_node()->nodeType == XML_ELEMENT_NODE )
844
+ break;
845
+
846
+ // Styles can only be applied directly to DOMElements; anonymous
847
+ // frames inherit from their parent
848
+ if ( $frame->get_node()->nodeType != XML_ELEMENT_NODE ) {
849
+ if ( $p )
850
+ $style->inherit($p->get_style());
851
+ $frame->set_style($style);
852
+ continue;
853
+ }
854
+
855
+ $id = $frame->get_id();
856
+
857
+ // Handle HTML 4.0 attributes
858
+ Attribute_Translator::translate_attributes($frame);
859
+ if ( ($str = $frame->get_node()->getAttribute(Attribute_Translator::$_style_attr)) !== "" ) {
860
+ // Lowest specificity
861
+ $styles[$id][1][] = $this->_parse_properties($str);
862
+ }
863
+
864
+ // Locate any additional style attributes
865
+ if ( ($str = $frame->get_node()->getAttribute("style")) !== "" ) {
866
+ // Destroy CSS comments
867
+ $str = preg_replace("'/\*.*?\*/'si", "", $str);
868
+
869
+ $spec = $this->_specificity("!attr");
870
+ $styles[$id][$spec][] = $this->_parse_properties($str);
871
+ }
872
+
873
+ // Grab the applicable styles
874
+ if ( isset($styles[$id]) ) {
875
+
876
+ $applied_styles = $styles[ $frame->get_id() ];
877
+
878
+ // Sort by specificity
879
+ ksort($applied_styles);
880
+
881
+ if (DEBUGCSS) {
882
+ $debug_nodename = $frame->get_node()->nodeName;
883
+ print "<pre>\n[$debug_nodename\n";
884
+ foreach ($applied_styles as $spec => $arr) {
885
+ printf("specificity: 0x%08x\n",$spec);
886
+ foreach ($arr as $s) {
887
+ print "[\n";
888
+ $s->debug_print();
889
+ print "]\n";
890
+ }
891
+ }
892
+ }
893
+
894
+ // Merge the new styles with the inherited styles
895
+ foreach ($applied_styles as $arr) {
896
+ foreach ($arr as $s)
897
+ $style->merge($s);
898
+ }
899
+ }
900
+
901
+ // Inherit parent's styles if required
902
+ if ( $p ) {
903
+
904
+ if (DEBUGCSS) {
905
+ print "inherit:\n";
906
+ print "[\n";
907
+ $p->get_style()->debug_print();
908
+ print "]\n";
909
+ }
910
+
911
+ $style->inherit( $p->get_style() );
912
+ }
913
+
914
+ if (DEBUGCSS) {
915
+ print "DomElementStyle:\n";
916
+ print "[\n";
917
+ $style->debug_print();
918
+ print "]\n";
919
+ print "/$debug_nodename]\n</pre>";
920
+ }
921
+
922
+ /*DEBUGCSS print: see below different print debugging method
923
+ pre_r($frame->get_node()->nodeName . ":");
924
+ echo "<pre>";
925
+ echo $style;
926
+ echo "</pre>";*/
927
+ $frame->set_style($style);
928
+
929
+ }
930
+
931
+ // We're done! Clean out the registry of all styles since we
932
+ // won't be needing this later.
933
+ foreach ( array_keys($this->_styles) as $key ) {
934
+ $this->_styles[$key] = null;
935
+ unset($this->_styles[$key]);
936
+ }
937
+
938
+ }
939
+
940
+
941
+ /**
942
+ * parse a CSS string using a regex parser
943
+ *
944
+ * Called by {@link Stylesheet::parse_css()}
945
+ *
946
+ * @param string $str
947
+ */
948
+ private function _parse_css($str) {
949
+
950
+ $str = trim($str);
951
+
952
+ // Destroy comments and remove HTML comments
953
+ $css = preg_replace(array(
954
+ "'/\*.*?\*/'si",
955
+ "/^<!--/",
956
+ "/-->$/"
957
+ ), "", $str);
958
+
959
+ // FIXME: handle '{' within strings, e.g. [attr="string {}"]
960
+
961
+ // Something more legible:
962
+ $re =
963
+ "/\s* # Skip leading whitespace \n".
964
+ "( @([^\s]+)\s+([^{;]*) (?:;|({)) )? # Match @rules followed by ';' or '{' \n".
965
+ "(?(1) # Only parse sub-sections if we're in an @rule... \n".
966
+ " (?(4) # ...and if there was a leading '{' \n".
967
+ " \s*( (?:(?>[^{}]+) ({)? # Parse rulesets and individual @page rules \n".
968
+ " (?(6) (?>[^}]*) }) \s*)+? \n".
969
+ " ) \n".
970
+ " }) # Balancing '}' \n".
971
+ "| # Branch to match regular rules (not preceeded by '@')\n".
972
+ "([^{]*{[^}]*})) # Parse normal rulesets\n".
973
+ "/xs";
974
+
975
+ if ( preg_match_all($re, $css, $matches, PREG_SET_ORDER) === false )
976
+ // An error occured
977
+ throw new DOMPDF_Exception("Error parsing css file: preg_match_all() failed.");
978
+
979
+ // After matching, the array indicies are set as follows:
980
+ //
981
+ // [0] => complete text of match
982
+ // [1] => contains '@import ...;' or '@media {' if applicable
983
+ // [2] => text following @ for cases where [1] is set
984
+ // [3] => media types or full text following '@import ...;'
985
+ // [4] => '{', if present
986
+ // [5] => rulesets within media rules
987
+ // [6] => '{', within media rules
988
+ // [7] => individual rules, outside of media rules
989
+ //
990
+ //pre_r($matches);
991
+ foreach ( $matches as $match ) {
992
+ $match[2] = trim($match[2]);
993
+
994
+ if ( $match[2] !== "" ) {
995
+ // Handle @rules
996
+ switch ($match[2]) {
997
+
998
+ case "import":
999
+ $this->_parse_import($match[3]);
1000
+ break;
1001
+
1002
+ case "media":
1003
+ $acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES;
1004
+
1005
+ if ( defined("DOMPDF_DEFAULT_MEDIA_TYPE") ) {
1006
+ $acceptedmedia[] = DOMPDF_DEFAULT_MEDIA_TYPE;
1007
+ }
1008
+ else {
1009
+ $acceptedmedia[] = self::$ACCEPTED_DEFAULT_MEDIA_TYPE;
1010
+ }
1011
+
1012
+ $media = preg_split("/\s*,\s*/", mb_strtolower(trim($match[3])));
1013
+
1014
+ if ( count(array_intersect($acceptedmedia, $media)) ) {
1015
+ $this->_parse_sections($match[5]);
1016
+ }
1017
+ break;
1018
+
1019
+ case "page":
1020
+ //This handles @page to be applied to page oriented media
1021
+ //Note: This has a reduced syntax:
1022
+ //@page { margin:1cm; color:blue; }
1023
+ //Not a sequence of styles like a full.css, but only the properties
1024
+ //of a single style, which is applied to the very first "root" frame before
1025
+ //processing other styles of the frame.
1026
+ //Working properties:
1027
+ // margin (for margin around edge of paper)
1028
+ // font-family (default font of pages)
1029
+ // color (default text color of pages)
1030
+ //Non working properties:
1031
+ // border
1032
+ // padding
1033
+ // background-color
1034
+ //Todo:Reason is unknown
1035
+ //Other properties (like further font or border attributes) not tested.
1036
+ //If a border or background color around each paper sheet is desired,
1037
+ //assign it to the <body> tag, possibly only for the css of the correct media type.
1038
+
1039
+ // If the page has a name, skip the style.
1040
+ $page_selector = trim($match[3]);
1041
+
1042
+ switch($page_selector) {
1043
+ case "":
1044
+ $key = "base";
1045
+ break;
1046
+
1047
+ case ":left":
1048
+ case ":right":
1049
+ case ":odd":
1050
+ case ":even":
1051
+ case ":first":
1052
+ $key = $page_selector;
1053
+
1054
+ default: continue;
1055
+ }
1056
+
1057
+ // Store the style for later...
1058
+ if ( empty($this->_page_styles[$key]) )
1059
+ $this->_page_styles[$key] = $this->_parse_properties($match[5]);
1060
+ else
1061
+ $this->_page_styles[$key]->merge($this->_parse_properties($match[5]));
1062
+ break;
1063
+
1064
+ case "font-face":
1065
+ $this->_parse_font_face($match[5]);
1066
+ break;
1067
+
1068
+ default:
1069
+ // ignore everything else
1070
+ break;
1071
+ }
1072
+
1073
+ continue;
1074
+ }
1075
+
1076
+ if ( $match[7] !== "" )
1077
+ $this->_parse_sections($match[7]);
1078
+
1079
+ }
1080
+ }
1081
+
1082
+ /* See also style.cls Style::_image(), refactoring?, works also for imported css files */
1083
+ protected function _image($val) {
1084
+ $DEBUGCSS=DEBUGCSS;
1085
+
1086
+ if ( mb_strpos($val, "url") === false ) {
1087
+ $path = "none"; //Don't resolve no image -> otherwise would prefix path and no longer recognize as none
1088
+ }
1089
+ else {
1090
+ $val = preg_replace("/url\(['\"]?([^'\")]+)['\"]?\)/","\\1", trim($val));
1091
+
1092
+ // Resolve the url now in the context of the current stylesheet
1093
+ $parsed_url = explode_url($val);
1094
+ if ( $parsed_url["protocol"] == "" && $this->get_protocol() == "" ) {
1095
+ if ($parsed_url["path"][0] === '/' || $parsed_url["path"][0] === '\\' ) {
1096
+ $path = $_SERVER["DOCUMENT_ROOT"].'/';
1097
+ } else {
1098
+ $path = $this->get_base_path();
1099
+ }
1100
+ $path .= $parsed_url["path"] . $parsed_url["file"];
1101
+ $path = realpath($path);
1102
+ // If realpath returns FALSE then specifically state that there is no background image
1103
+ // FIXME: Is this causing problems for imported CSS files? There are some './none' references when running the test cases.
1104
+ if (!$path) { $path = 'none'; }
1105
+ } else {
1106
+ $path = build_url($this->get_protocol(),
1107
+ $this->get_host(),
1108
+ $this->get_base_path(),
1109
+ $val);
1110
+ }
1111
+ }
1112
+ if ($DEBUGCSS) {
1113
+ print "<pre>[_image\n";
1114
+ print_r($parsed_url);
1115
+ print $this->get_protocol()."\n".$this->get_base_path()."\n".$path."\n";
1116
+ print "_image]</pre>";;
1117
+ }
1118
+ return $path;
1119
+ }
1120
+
1121
+ /**
1122
+ * parse @import{} sections
1123
+ *
1124
+ * @param string $url the url of the imported CSS file
1125
+ */
1126
+ private function _parse_import($url) {
1127
+ $arr = preg_split("/[\s\n,]/", $url,-1, PREG_SPLIT_NO_EMPTY);
1128
+ $url = array_shift($arr);
1129
+ $accept = false;
1130
+
1131
+ if ( count($arr) > 0 ) {
1132
+
1133
+ $acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES;
1134
+ if ( defined("DOMPDF_DEFAULT_MEDIA_TYPE") ) {
1135
+ $acceptedmedia[] = DOMPDF_DEFAULT_MEDIA_TYPE;
1136
+ } else {
1137
+ $acceptedmedia[] = self::$ACCEPTED_DEFAULT_MEDIA_TYPE;
1138
+ }
1139
+
1140
+ // @import url media_type [media_type...]
1141
+ foreach ( $arr as $type ) {
1142
+ if ( in_array(mb_strtolower(trim($type)), $acceptedmedia) ) {
1143
+ $accept = true;
1144
+ break;
1145
+ }
1146
+ }
1147
+
1148
+ } else {
1149
+ // unconditional import
1150
+ $accept = true;
1151
+ }
1152
+
1153
+ if ( $accept ) {
1154
+ // Store our current base url properties in case the new url is elsewhere
1155
+ $protocol = $this->_protocol;
1156
+ $host = $this->_base_host;
1157
+ $path = $this->_base_path;
1158
+
1159
+ // $url = str_replace(array('"',"url", "(", ")"), "", $url);
1160
+ // If the protocol is php, assume that we will import using file://
1161
+ // $url = build_url($protocol == "php://" ? "file://" : $protocol, $host, $path, $url);
1162
+ // Above does not work for subfolders and absolute urls.
1163
+ // Todo: As above, do we need to replace php or file to an empty protocol for local files?
1164
+
1165
+ $url = $this->_image($url);
1166
+
1167
+ $this->load_css_file($url);
1168
+
1169
+ // Restore the current base url
1170
+ $this->_protocol = $protocol;
1171
+ $this->_base_host = $host;
1172
+ $this->_base_path = $path;
1173
+ }
1174
+
1175
+ }
1176
+
1177
+ /**
1178
+ * parse @font-face{} sections
1179
+ * http://www.w3.org/TR/css3-fonts/#the-font-face-rule
1180
+ *
1181
+ * @param string $str CSS @font-face rules
1182
+ * @return Style
1183
+ */
1184
+ private function _parse_font_face($str) {
1185
+ $descriptors = $this->_parse_properties($str);
1186
+
1187
+ preg_match_all("/(url|local)\s*\([\"\']?([^\"\'\)]+)[\"\']?\)\s*(format\s*\([\"\']?([^\"\'\)]+)[\"\']?\))?/i", $descriptors->src, $src);
1188
+
1189
+ $sources = array();
1190
+ $valid_sources = array();
1191
+
1192
+ foreach($src[0] as $i => $value) {
1193
+ $source = array(
1194
+ "local" => strtolower($src[1][$i]) === "local",
1195
+ "uri" => $src[2][$i],
1196
+ "format" => $src[4][$i],
1197
+ "path" => build_url($this->_protocol, $this->_base_host, $this->_base_path, $src[2][$i]),
1198
+ );
1199
+
1200
+ if ( !$source["local"] && in_array($source["format"], array("", "woff", "opentype", "truetype")) ) {
1201
+ $valid_sources[] = $source;
1202
+ }
1203
+
1204
+ $sources[] = $source;
1205
+ }
1206
+
1207
+ // No valid sources
1208
+ if ( empty($valid_sources) ) {
1209
+ return;
1210
+ }
1211
+
1212
+ $style = array(
1213
+ "family" => $descriptors->get_font_family_raw(),
1214
+ "weight" => $descriptors->font_weight,
1215
+ "style" => $descriptors->font_style,
1216
+ );
1217
+
1218
+ Font_Metrics::register_font($style, $valid_sources[0]["path"]);
1219
+ }
1220
+
1221
+ /**
1222
+ * parse regular CSS blocks
1223
+ *
1224
+ * _parse_properties() creates a new Style object based on the provided
1225
+ * CSS rules.
1226
+ *
1227
+ * @param string $str CSS rules
1228
+ * @return Style
1229
+ */
1230
+ private function _parse_properties($str) {
1231
+ $properties = preg_split("/;(?=(?:[^\(]*\([^\)]*\))*(?![^\)]*\)))/", $str);
1232
+
1233
+ if (DEBUGCSS) print '[_parse_properties';
1234
+
1235
+ // Create the style
1236
+ $style = new Style($this);
1237
+
1238
+ foreach ($properties as $prop) {
1239
+ // If the $prop contains an url, the regex may be wrong
1240
+ // @todo: fix the regex so that it works everytime
1241
+ /*if (strpos($prop, "url(") === false) {
1242
+ if (preg_match("/([a-z-]+)\s*:\s*[^:]+$/i", $prop, $m))
1243
+ $prop = $m[0];
1244
+ }*/
1245
+ //A css property can have " ! important" appended (whitespace optional)
1246
+ //strip this off to decode core of the property correctly.
1247
+ //Pass on in the style to allow proper handling:
1248
+ //!important properties can only be overridden by other !important ones.
1249
+ //$style->$prop_name = is a shortcut of $style->__set($prop_name,$value);.
1250
+ //If no specific set function available, set _props["prop_name"]
1251
+ //style is always copied completely, or $_props handled separately
1252
+ //Therefore set a _important_props["prop_name"]=true to indicate the modifier
1253
+
1254
+ /* Instead of short code, prefer the typical case with fast code
1255
+ $important = preg_match("/(.*?)!\s*important/",$prop,$match);
1256
+ if ( $important ) {
1257
+ $prop = $match[1];
1258
+ }
1259
+ $prop = trim($prop);
1260
+ */
1261
+ if (DEBUGCSS) print '(';
1262
+
1263
+ $important = false;
1264
+ $prop = trim($prop);
1265
+
1266
+ if ( substr($prop, -9) === 'important' ) {
1267
+ $prop_tmp = rtrim(substr($prop, 0, -9));
1268
+
1269
+ if ( substr($prop_tmp, -1) === '!' ) {
1270
+ $prop = rtrim(substr($prop_tmp, 0, -1));
1271
+ $important = true;
1272
+ }
1273
+ }
1274
+
1275
+ if ( $prop === "" ) {
1276
+ if (DEBUGCSS) print 'empty)';
1277
+ continue;
1278
+ }
1279
+
1280
+ $i = mb_strpos($prop, ":");
1281
+ if ( $i === false ) {
1282
+ if (DEBUGCSS) print 'novalue'.$prop.')';
1283
+ continue;
1284
+ }
1285
+
1286
+ $prop_name = rtrim(mb_strtolower(mb_substr($prop, 0, $i)));
1287
+ $value = ltrim(mb_substr($prop, $i+1));
1288
+ if (DEBUGCSS) print $prop_name.':='.$value.($important?'!IMPORTANT':'').')';
1289
+ //New style, anyway empty
1290
+ //if ($important || !$style->important_get($prop_name) ) {
1291
+ //$style->$prop_name = array($value,$important);
1292
+ //assignment might be replaced by overloading through __set,
1293
+ //and overloaded functions might check _important_props,
1294
+ //therefore set _important_props first.
1295
+ if ($important) {
1296
+ $style->important_set($prop_name);
1297
+ }
1298
+ //For easier debugging, don't use overloading of assignments with __set
1299
+ $style->$prop_name = $value;
1300
+ //$style->props_set($prop_name, $value);
1301
+ }
1302
+ if (DEBUGCSS) print '_parse_properties]';
1303
+
1304
+ return $style;
1305
+ }
1306
+
1307
+ /**
1308
+ * parse selector + rulesets
1309
+ *
1310
+ * @param string $str CSS selectors and rulesets
1311
+ */
1312
+ private function _parse_sections($str) {
1313
+ // Pre-process: collapse all whitespace and strip whitespace around '>',
1314
+ // '.', ':', '+', '#'
1315
+
1316
+ $patterns = array("/[\\s\n]+/", "/\\s+([>.:+#])\\s+/");
1317
+ $replacements = array(" ", "\\1");
1318
+ $str = preg_replace($patterns, $replacements, $str);
1319
+
1320
+ $sections = explode("}", $str);
1321
+ if (DEBUGCSS) print '[_parse_sections';
1322
+ foreach ($sections as $sect) {
1323
+ $i = mb_strpos($sect, "{");
1324
+
1325
+ $selectors = explode(",", mb_substr($sect, 0, $i));
1326
+ if (DEBUGCSS) print '[section';
1327
+ $style = $this->_parse_properties(trim(mb_substr($sect, $i+1)));
1328
+
1329
+ // Assign it to the selected elements
1330
+ foreach ($selectors as $selector) {
1331
+ $selector = trim($selector);
1332
+
1333
+ if ($selector == "") {
1334
+ if (DEBUGCSS) print '#empty#';
1335
+ continue;
1336
+ }
1337
+ if (DEBUGCSS) print '#'.$selector.'#';
1338
+ //if (DEBUGCSS) { if (strpos($selector,'p') !== false) print '!!!p!!!#'; }
1339
+
1340
+ $this->add_style($selector, $style);
1341
+ }
1342
+ if (DEBUGCSS) print 'section]';
1343
+ }
1344
+ if (DEBUGCSS) print '_parse_sections]';
1345
+ }
1346
+
1347
+ /**
1348
+ * dumps the entire stylesheet as a string
1349
+ *
1350
+ * Generates a string of each selector and associated style in the
1351
+ * Stylesheet. Useful for debugging.
1352
+ *
1353
+ * @return string
1354
+ */
1355
+ function __toString() {
1356
+ $str = "";
1357
+ foreach ($this->_styles as $selector => $style)
1358
+ $str .= "$selector => " . $style->__toString() . "\n";
1359
+
1360
+ return $str;
1361
+ }
1362
+ }
dompdf/include/table_cell_frame_decorator.cls.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_cell_frame_decorator.cls.php 451 2012-01-14 14:54:23Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Decorates table cells for layout
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Cell_Frame_Decorator extends Block_Frame_Decorator {
17
+
18
+ protected $_resolved_borders;
19
+ protected $_content_height;
20
+
21
+ //........................................................................
22
+
23
+ function __construct(Frame $frame, DOMPDF $dompdf) {
24
+ parent::__construct($frame, $dompdf);
25
+ $this->_resolved_borders = array();
26
+ $this->_content_height = 0;
27
+ }
28
+
29
+ //........................................................................
30
+
31
+ function reset() {
32
+ parent::reset();
33
+ $this->_resolved_borders = array();
34
+ $this->_content_height = 0;
35
+ $this->_frame->reset();
36
+ }
37
+
38
+ function get_content_height() {
39
+ return $this->_content_height;
40
+ }
41
+
42
+ function set_content_height($height) {
43
+ $this->_content_height = $height;
44
+ }
45
+
46
+ function set_cell_height($height) {
47
+ $style = $this->get_style();
48
+ $v_space = $style->length_in_pt(array($style->margin_top,
49
+ $style->padding_top,
50
+ $style->border_top_width,
51
+ $style->border_bottom_width,
52
+ $style->padding_bottom,
53
+ $style->margin_bottom),
54
+ $style->width);
55
+
56
+ $new_height = $height - $v_space;
57
+ $style->height = $new_height;
58
+
59
+ if ( $new_height > $this->_content_height ) {
60
+ $y_offset = 0;
61
+
62
+ // Adjust our vertical alignment
63
+ switch ($style->vertical_align) {
64
+ default:
65
+ case "baseline":
66
+ // FIXME: this isn't right
67
+
68
+ case "top":
69
+ // Don't need to do anything
70
+ return;
71
+
72
+ case "middle":
73
+ $y_offset = ($new_height - $this->_content_height) / 2;
74
+ break;
75
+
76
+ case "bottom":
77
+ $y_offset = $new_height - $this->_content_height;
78
+ break;
79
+ }
80
+
81
+ if ( $y_offset ) {
82
+ // Move our children
83
+ foreach ( $this->get_line_boxes() as $i => $line ) {
84
+ foreach ( $line->get_frames() as $frame )
85
+ $frame->move( 0, $y_offset );
86
+ }
87
+ }
88
+ }
89
+
90
+ }
91
+
92
+ function set_resolved_border($side, $border_spec) {
93
+ $this->_resolved_borders[$side] = $border_spec;
94
+ }
95
+
96
+ //........................................................................
97
+
98
+ function get_resolved_border($side) {
99
+ return $this->_resolved_borders[$side];
100
+ }
101
+
102
+ function get_resolved_borders() { return $this->_resolved_borders; }
103
+ }
dompdf/include/table_cell_frame_reflower.cls.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_cell_frame_reflower.cls.php 457 2012-01-22 11:48:20Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Reflows table cells
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Cell_Frame_Reflower extends Block_Frame_Reflower {
17
+
18
+ //........................................................................
19
+
20
+ function __construct(Frame $frame) {
21
+ parent::__construct($frame);
22
+ }
23
+
24
+ //........................................................................
25
+
26
+ function reflow(Frame_Decorator $block = null) {
27
+
28
+ $style = $this->_frame->get_style();
29
+
30
+ $table = Table_Frame_Decorator::find_parent_table($this->_frame);
31
+ $cellmap = $table->get_cellmap();
32
+
33
+ list($x, $y) = $cellmap->get_frame_position($this->_frame);
34
+ $this->_frame->set_position($x, $y);
35
+
36
+ $cells = $cellmap->get_spanned_cells($this->_frame);
37
+
38
+ $w = 0;
39
+ foreach ( $cells["columns"] as $i ) {
40
+ $col = $cellmap->get_column( $i );
41
+ $w += $col["used-width"];
42
+ }
43
+
44
+ //FIXME?
45
+ $h = $this->_frame->get_containing_block("h");
46
+
47
+ $left_space = $style->length_in_pt(array($style->margin_left,
48
+ $style->padding_left,
49
+ $style->border_left_width),
50
+ $w);
51
+
52
+ $right_space = $style->length_in_pt(array($style->padding_right,
53
+ $style->margin_right,
54
+ $style->border_right_width),
55
+ $w);
56
+
57
+ $top_space = $style->length_in_pt(array($style->margin_top,
58
+ $style->padding_top,
59
+ $style->border_top_width),
60
+ $h);
61
+ $bottom_space = $style->length_in_pt(array($style->margin_bottom,
62
+ $style->padding_bottom,
63
+ $style->border_bottom_width),
64
+ $h);
65
+
66
+ $style->width = $cb_w = $w - $left_space - $right_space;
67
+
68
+ $content_x = $x + $left_space;
69
+ $content_y = $line_y = $y + $top_space;
70
+
71
+ // Adjust the first line based on the text-indent property
72
+ $indent = $style->length_in_pt($style->text_indent, $w);
73
+ $this->_frame->increase_line_width($indent);
74
+
75
+ // Set the y position of the first line in the cell
76
+ $page = $this->_frame->get_root();
77
+ $this->_frame->set_current_line($line_y);
78
+
79
+ // Set the containing blocks and reflow each child
80
+ foreach ( $this->_frame->get_children() as $child ) {
81
+
82
+ if ( $page->is_full() )
83
+ break;
84
+
85
+ $child->set_containing_block($content_x, $content_y, $cb_w, $h);
86
+ $child->reflow($this->_frame);
87
+
88
+ $this->process_float($child, $x + $left_space, $w - $right_space - $left_space);
89
+ }
90
+
91
+ // Determine our height
92
+ $style_height = $style->length_in_pt($style->height, $h);
93
+
94
+ $this->_frame->set_content_height($this->_calculate_content_height());
95
+
96
+ $height = max($style_height, $this->_frame->get_content_height());
97
+
98
+ // Let the cellmap know our height
99
+ $cell_height = $height / count($cells["rows"]);
100
+
101
+ if ($style_height <= $height)
102
+ $cell_height += $top_space + $bottom_space;
103
+
104
+ foreach ($cells["rows"] as $i)
105
+ $cellmap->set_row_height($i, $cell_height);
106
+
107
+ $style->height = $height;
108
+
109
+ $this->_text_align();
110
+
111
+ $this->vertical_align();
112
+
113
+ }
114
+
115
+ }
dompdf/include/table_cell_positioner.cls.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_cell_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Positions table cells
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Cell_Positioner extends Positioner {
17
+
18
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
19
+
20
+ //........................................................................
21
+
22
+ function position() {
23
+
24
+ $table = Table_Frame_Decorator::find_parent_table($this->_frame);
25
+ $cellmap = $table->get_cellmap();
26
+ $this->_frame->set_position($cellmap->get_frame_position($this->_frame));
27
+
28
+ }
29
+ }
dompdf/include/table_cell_renderer.cls.php ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_cell_renderer.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Renders table cells
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Cell_Renderer extends Block_Renderer {
17
+
18
+ //........................................................................
19
+
20
+ function render(Frame $frame) {
21
+ $style = $frame->get_style();
22
+
23
+ if ( trim($frame->get_node()->nodeValue) === "" && $style->empty_cells === "hide" ) {
24
+ return;
25
+ }
26
+
27
+ $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
28
+ list($x, $y, $w, $h) = $frame->get_border_box();
29
+
30
+ // Draw our background, border and content
31
+ if ( ($bg = $style->background_color) !== "transparent" ) {
32
+ $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
33
+ }
34
+
35
+ if ( ($url = $style->background_image) && $url !== "none" ) {
36
+ $this->_background_image($url, $x, $y, $w, $h, $style);
37
+ }
38
+
39
+ $table = Table_Frame_Decorator::find_parent_table($frame);
40
+
41
+ if ( $table->get_style()->border_collapse !== "collapse" ) {
42
+ $this->_render_border($frame);
43
+ $this->_render_outline($frame);
44
+ return;
45
+ }
46
+
47
+ // The collapsed case is slightly complicated...
48
+ // @todo Add support for outlines here
49
+
50
+ $cellmap = $table->get_cellmap();
51
+ $cells = $cellmap->get_spanned_cells($frame);
52
+ $num_rows = $cellmap->get_num_rows();
53
+ $num_cols = $cellmap->get_num_cols();
54
+
55
+ // Determine the top row spanned by this cell
56
+ $i = $cells["rows"][0];
57
+ $top_row = $cellmap->get_row($i);
58
+
59
+ // Determine if this cell borders on the bottom of the table. If so,
60
+ // then we draw its bottom border. Otherwise the next row down will
61
+ // draw its top border instead.
62
+ if (in_array( $num_rows - 1, $cells["rows"])) {
63
+ $draw_bottom = true;
64
+ $bottom_row = $cellmap->get_row($num_rows - 1);
65
+ } else
66
+ $draw_bottom = false;
67
+
68
+
69
+ // Draw the horizontal borders
70
+ foreach ( $cells["columns"] as $j ) {
71
+ $bp = $cellmap->get_border_properties($i, $j);
72
+
73
+ $y = $top_row["y"] - $bp["top"]["width"] / 2;
74
+
75
+ $col = $cellmap->get_column($j);
76
+ $x = $col["x"] - $bp["left"]["width"] / 2;
77
+ $w = $col["used-width"] + ($bp["left"]["width"] + $bp["right"]["width"] ) / 2;
78
+
79
+ if ( $bp["top"]["style"] !== "none" && $bp["top"]["width"] > 0 ) {
80
+ $widths = array($bp["top"]["width"],
81
+ $bp["right"]["width"],
82
+ $bp["bottom"]["width"],
83
+ $bp["left"]["width"]);
84
+ $method = "_border_". $bp["top"]["style"];
85
+ $this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top", "square");
86
+ }
87
+
88
+ if ( $draw_bottom ) {
89
+ $bp = $cellmap->get_border_properties($num_rows - 1, $j);
90
+ if ( $bp["bottom"]["style"] === "none" || $bp["bottom"]["width"] <= 0 )
91
+ continue;
92
+
93
+ $y = $bottom_row["y"] + $bottom_row["height"] + $bp["bottom"]["width"] / 2;
94
+
95
+ $widths = array($bp["top"]["width"],
96
+ $bp["right"]["width"],
97
+ $bp["bottom"]["width"],
98
+ $bp["left"]["width"]);
99
+ $method = "_border_". $bp["bottom"]["style"];
100
+ $this->$method($x, $y, $w, $bp["bottom"]["color"], $widths, "bottom", "square");
101
+
102
+ }
103
+ }
104
+
105
+ $j = $cells["columns"][0];
106
+
107
+ $left_col = $cellmap->get_column($j);
108
+
109
+ if (in_array($num_cols - 1, $cells["columns"])) {
110
+ $draw_right = true;
111
+ $right_col = $cellmap->get_column($num_cols - 1);
112
+ } else
113
+ $draw_right = false;
114
+
115
+ // Draw the vertical borders
116
+ foreach ( $cells["rows"] as $i ) {
117
+ $bp = $cellmap->get_border_properties($i, $j);
118
+
119
+ $x = $left_col["x"] - $bp["left"]["width"] / 2;
120
+
121
+ $row = $cellmap->get_row($i);
122
+
123
+ $y = $row["y"] - $bp["top"]["width"] / 2;
124
+ $h = $row["height"] + ($bp["top"]["width"] + $bp["bottom"]["width"])/ 2;
125
+
126
+ if ( $bp["left"]["style"] !== "none" && $bp["left"]["width"] > 0 ) {
127
+
128
+ $widths = array($bp["top"]["width"],
129
+ $bp["right"]["width"],
130
+ $bp["bottom"]["width"],
131
+ $bp["left"]["width"]);
132
+
133
+ $method = "_border_" . $bp["left"]["style"];
134
+ $this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left", "square");
135
+ }
136
+
137
+ if ( $draw_right ) {
138
+ $bp = $cellmap->get_border_properties($i, $num_cols - 1);
139
+ if ( $bp["right"]["style"] === "none" || $bp["right"]["width"] <= 0 )
140
+ continue;
141
+
142
+ $x = $right_col["x"] + $right_col["used-width"] + $bp["right"]["width"] / 2;
143
+
144
+ $widths = array($bp["top"]["width"],
145
+ $bp["right"]["width"],
146
+ $bp["bottom"]["width"],
147
+ $bp["left"]["width"]);
148
+
149
+ $method = "_border_" . $bp["right"]["style"];
150
+ $this->$method($x, $y, $h, $bp["right"]["color"], $widths, "right", "square");
151
+
152
+ }
153
+ }
154
+
155
+ }
156
+ }
dompdf/include/table_frame_decorator.cls.php ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_frame_decorator.cls.php 462 2012-01-29 22:44:23Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Decorates Frames for table layout
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Frame_Decorator extends Frame_Decorator {
17
+ static $VALID_CHILDREN = array("table-row-group",
18
+ "table-row",
19
+ "table-header-group",
20
+ "table-footer-group",
21
+ "table-column",
22
+ "table-column-group",
23
+ "table-caption",
24
+ "table-cell");
25
+
26
+ static $ROW_GROUPS = array('table-row-group',
27
+ 'table-header-group',
28
+ 'table-footer-group');
29
+
30
+ /**
31
+ * The Cellmap object for this table. The cellmap maps table cells
32
+ * to rows and columns, and aids in calculating column widths.
33
+ *
34
+ * @var Cellmap
35
+ */
36
+ protected $_cellmap;
37
+
38
+ /**
39
+ * The minimum width of the table, in pt
40
+ *
41
+ * @var float
42
+ */
43
+ protected $_min_width;
44
+
45
+ /**
46
+ * The maximum width of the table, in pt
47
+ *
48
+ * @var float
49
+ */
50
+ protected $_max_width;
51
+
52
+ /**
53
+ * Table header rows. Each table header is duplicated when a table
54
+ * spans pages.
55
+ *
56
+ * @var array
57
+ */
58
+ protected $_headers;
59
+
60
+ /**
61
+ * Table footer rows. Each table footer is duplicated when a table
62
+ * spans pages.
63
+ *
64
+ * @var array
65
+ */
66
+ protected $_footers;
67
+
68
+ /**
69
+ * Class constructor
70
+ *
71
+ * @param Frame $frame the frame to decorate
72
+ */
73
+ function __construct(Frame $frame, DOMPDF $dompdf) {
74
+ parent::__construct($frame, $dompdf);
75
+ $this->_cellmap = new Cellmap($this);
76
+ $this->_min_width = null;
77
+ $this->_max_width = null;
78
+ $this->_headers = array();
79
+ $this->_footers = array();
80
+ }
81
+
82
+
83
+ function reset() {
84
+ parent::reset();
85
+ $this->_cellmap->reset();
86
+ $this->_min_width = null;
87
+ $this->_max_width = null;
88
+ $this->_headers = array();
89
+ $this->_footers = array();
90
+ $this->_reflower->reset();
91
+ }
92
+
93
+ //........................................................................
94
+
95
+ /**
96
+ * split the table at $row. $row and all subsequent rows will be
97
+ * added to the clone. This method is overidden in order to remove
98
+ * frames from the cellmap properly.
99
+ *
100
+ * @param Frame $row
101
+ */
102
+ function split($child = null, $force_pagebreak = false) {
103
+
104
+ if ( is_null($child) ) {
105
+ parent::split();
106
+ return;
107
+ }
108
+
109
+ // If $child is a header or if it is the first non-header row, do
110
+ // not duplicate headers, simply move the table to the next page.
111
+ if ( count($this->_headers) && !in_array($child, $this->_headers, true) &&
112
+ !in_array($child->get_prev_sibling(), $this->_headers, true) ) {
113
+
114
+ $first_header = null;
115
+
116
+ // Insert copies of the table headers before $child
117
+ foreach ($this->_headers as $header) {
118
+
119
+ $new_header = $header->deep_copy();
120
+
121
+ if ( is_null($first_header) )
122
+ $first_header = $new_header;
123
+
124
+ $this->insert_child_before($new_header, $child);
125
+ }
126
+
127
+ parent::split($first_header);
128
+
129
+ } else if ( in_array($child->get_style()->display, self::$ROW_GROUPS) ) {
130
+
131
+ // Individual rows should have already been handled
132
+ parent::split($child);
133
+
134
+ } else {
135
+
136
+ $iter = $child;
137
+
138
+ while ($iter) {
139
+ $this->_cellmap->remove_row($iter);
140
+ $iter = $iter->get_next_sibling();
141
+ }
142
+
143
+ parent::split($child);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Return a copy of this frame with $node as its node
149
+ *
150
+ * @param DomNode $node
151
+ * @return Frame
152
+ */
153
+ function copy(DomNode $node) {
154
+ $deco = parent::copy($node);
155
+
156
+ // In order to keep columns' widths through pages
157
+ $deco->_cellmap->set_columns($this->_cellmap->get_columns());
158
+ $deco->_cellmap->lock_columns();
159
+
160
+ return $deco;
161
+ }
162
+
163
+ /**
164
+ * Static function to locate the parent table of a frame
165
+ *
166
+ * @param Frame $frame
167
+ * @return Table_Frame_Decorator the table that is an ancestor of $frame
168
+ */
169
+ static function find_parent_table(Frame $frame) {
170
+
171
+ while ( $frame = $frame->get_parent() )
172
+ if ( $frame->is_table() )
173
+ break;
174
+
175
+ return $frame;
176
+ }
177
+
178
+ /**
179
+ * Return this table's Cellmap
180
+ *
181
+ * @return Cellmap
182
+ */
183
+ function get_cellmap() { return $this->_cellmap; }
184
+
185
+ /**
186
+ * Return the minimum width of this table
187
+ *
188
+ * @return float
189
+ */
190
+ function get_min_width() { return $this->_min_width; }
191
+
192
+ /**
193
+ * Return the maximum width of this table
194
+ *
195
+ * @return float
196
+ */
197
+ function get_max_width() { return $this->_max_width; }
198
+
199
+ /**
200
+ * Set the minimum width of the table
201
+ *
202
+ * @param float $width the new minimum width
203
+ */
204
+ function set_min_width($width) { $this->_min_width = $width; }
205
+
206
+ /**
207
+ * Set the maximum width of the table
208
+ *
209
+ * @param float $width the new maximum width
210
+ */
211
+ function set_max_width($width) { $this->_max_width = $width; }
212
+
213
+ /**
214
+ * Restructure tree so that the table has the correct structure.
215
+ * Invalid children (i.e. all non-table-rows) are moved below the
216
+ * table.
217
+ */
218
+ function normalise() {
219
+
220
+ // Store frames generated by invalid tags and move them outside the table
221
+ $erroneous_frames = array();
222
+ $anon_row = false;
223
+ $iter = $this->get_first_child();
224
+ while ( $iter ) {
225
+ $child = $iter;
226
+ $iter = $iter->get_next_sibling();
227
+
228
+ $display = $child->get_style()->display;
229
+
230
+ if ( $anon_row ) {
231
+
232
+ if ( $display === "table-row" ) {
233
+ // Add the previous anonymous row
234
+ $this->insert_child_before($table_row, $child);
235
+
236
+ $table_row->normalise();
237
+ $child->normalise();
238
+ $anon_row = false;
239
+ continue;
240
+ }
241
+
242
+ // add the child to the anonymous row
243
+ $table_row->append_child($child);
244
+ continue;
245
+
246
+ } else {
247
+
248
+ if ( $display === "table-row" ) {
249
+ $child->normalise();
250
+ continue;
251
+ }
252
+
253
+ if ( $display === "table-cell" ) {
254
+ // Create an anonymous table row
255
+ $tr = $this->get_node()->ownerDocument->createElement("tr");
256
+
257
+ $frame = new Frame($tr);
258
+
259
+ $css = $this->get_style()->get_stylesheet();
260
+ $style = $css->create_style();
261
+ $style->inherit($this->get_style());
262
+
263
+ // Lookup styles for tr tags. If the user wants styles to work
264
+ // better, they should make the tr explicit... I'm not going to
265
+ // try to guess what they intended.
266
+ if ( $tr_style = $css->lookup("tr") )
267
+ $style->merge($tr_style);
268
+
269
+ // Okay, I have absolutely no idea why I need this clone here, but
270
+ // if it's omitted, php (as of 2004-07-28) segfaults.
271
+ $frame->set_style(clone $style);
272
+ $table_row = Frame_Factory::decorate_frame($frame, $this->_dompdf);
273
+ $table_row->set_root($this->_root);
274
+
275
+ // Add the cell to the row
276
+ $table_row->append_child($child);
277
+
278
+ $anon_row = true;
279
+ continue;
280
+ }
281
+
282
+ if ( !in_array($display, self::$VALID_CHILDREN) ) {
283
+ $erroneous_frames[] = $child;
284
+ continue;
285
+ }
286
+
287
+ // Normalise other table parts (i.e. row groups)
288
+ foreach ($child->get_children() as $grandchild) {
289
+ if ( $grandchild->get_style()->display === "table-row" )
290
+ $grandchild->normalise();
291
+ }
292
+
293
+ // Add headers and footers
294
+ if ( $display === "table-header-group" )
295
+ $this->_headers[] = $child;
296
+
297
+ else if ( $display === "table-footer-group" )
298
+ $this->_footers[] = $child;
299
+ }
300
+ }
301
+
302
+ if ( $anon_row ) {
303
+ // Add the row to the table
304
+ $this->_frame->append_child($table_row);
305
+ $table_row->normalise();
306
+ $this->_cellmap->add_row();
307
+ }
308
+
309
+ foreach ($erroneous_frames as $frame)
310
+ $this->move_after($frame);
311
+
312
+ }
313
+
314
+ //........................................................................
315
+
316
+ /**
317
+ * Moves the specified frame and it's corresponding node outside of
318
+ * the table.
319
+ *
320
+ * @param Frame $frame the frame to move
321
+ */
322
+ function move_after(Frame $frame) {
323
+ $this->get_parent()->insert_child_after($frame, $this);
324
+ }
325
+
326
+ }
dompdf/include/table_frame_reflower.cls.php ADDED
@@ -0,0 +1,567 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_frame_reflower.cls.php 465 2012-01-30 21:58:11Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Reflows tables
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Frame_Reflower extends Frame_Reflower {
17
+
18
+ /**
19
+ * Cache of results between call to get_min_max_width and assign_widths
20
+ *
21
+ * @var array
22
+ */
23
+ protected $_state;
24
+
25
+ function __construct(Table_Frame_Decorator $frame) {
26
+ $this->_state = null;
27
+ parent::__construct($frame);
28
+ }
29
+
30
+ /**
31
+ * State is held here so it needs to be reset along with the decorator
32
+ */
33
+ function reset() {
34
+ $this->_state = null;
35
+ $this->_min_max_cache = null;
36
+ }
37
+
38
+ //........................................................................
39
+
40
+ protected function _assign_widths() {
41
+ $style = $this->_frame->get_style();
42
+
43
+ // Find the min/max width of the table and sort the columns into
44
+ // absolute/percent/auto arrays
45
+ $min_width = $this->_state["min_width"];
46
+ $max_width = $this->_state["max_width"];
47
+ $percent_used = $this->_state["percent_used"];
48
+ $absolute_used = $this->_state["absolute_used"];
49
+ $auto_min = $this->_state["auto_min"];
50
+
51
+ $absolute =& $this->_state["absolute"];
52
+ $percent =& $this->_state["percent"];
53
+ $auto =& $this->_state["auto"];
54
+
55
+ // Determine the actual width of the table
56
+ $cb = $this->_frame->get_containing_block();
57
+ $columns =& $this->_frame->get_cellmap()->get_columns();
58
+
59
+ $width = $style->width;
60
+
61
+ // Calculate padding & border fudge factor
62
+ $left = $style->margin_left;
63
+ $right = $style->margin_right;
64
+
65
+ $centered = ( $left === "auto" && $right === "auto" );
66
+
67
+ $left = $left === "auto" ? 0 : $style->length_in_pt($left, $cb["w"]);
68
+ $right = $right === "auto" ? 0 : $style->length_in_pt($right, $cb["w"]);
69
+
70
+ $delta = $left + $right;
71
+
72
+ if ( !$centered ) {
73
+ $delta += $style->length_in_pt(array(
74
+ $style->padding_left,
75
+ $style->border_left_width,
76
+ $style->border_right_width,
77
+ $style->padding_right),
78
+ $cb["w"]);
79
+ }
80
+
81
+ $min_table_width = $style->length_in_pt( $style->min_width, $cb["w"] - $delta );
82
+
83
+ // min & max widths already include borders & padding
84
+ $min_width -= $delta;
85
+ $max_width -= $delta;
86
+
87
+ if ( $width !== "auto" ) {
88
+
89
+ $preferred_width = $style->length_in_pt($width, $cb["w"]) - $delta;
90
+
91
+ if ( $preferred_width < $min_table_width )
92
+ $preferred_width = $min_table_width;
93
+
94
+ if ( $preferred_width > $min_width )
95
+ $width = $preferred_width;
96
+ else
97
+ $width = $min_width;
98
+
99
+ } else {
100
+
101
+ if ( $max_width + $delta < $cb["w"] )
102
+ $width = $max_width;
103
+ else if ( $cb["w"] - $delta > $min_width )
104
+ $width = $cb["w"] - $delta;
105
+ else
106
+ $width = $min_width;
107
+
108
+ if ( $width < $min_table_width )
109
+ $width = $min_table_width;
110
+
111
+ }
112
+
113
+ // Store our resolved width
114
+ $style->width = $width;
115
+
116
+ $cellmap = $this->_frame->get_cellmap();
117
+
118
+ if ( $cellmap->is_columns_locked() ) {
119
+ return;
120
+ }
121
+
122
+ // If the whole table fits on the page, then assign each column it's max width
123
+ if ( $width == $max_width ) {
124
+
125
+ foreach (array_keys($columns) as $i)
126
+ $cellmap->set_column_width($i, $columns[$i]["max-width"]);
127
+
128
+ return;
129
+ }
130
+
131
+ // Determine leftover and assign it evenly to all columns
132
+ if ( $width > $min_width ) {
133
+
134
+ // We have four cases to deal with:
135
+ //
136
+ // 1. All columns are auto--no widths have been specified. In this
137
+ // case we distribute extra space across all columns weighted by max-width.
138
+ //
139
+ // 2. Only absolute widths have been specified. In this case we
140
+ // distribute any extra space equally among 'width: auto' columns, or all
141
+ // columns if no auto columns have been specified.
142
+ //
143
+ // 3. Only percentage widths have been specified. In this case we
144
+ // normalize the percentage values and distribute any remaining % to
145
+ // width: auto columns. We then proceed to assign widths as fractions
146
+ // of the table width.
147
+ //
148
+ // 4. Both absolute and percentage widths have been specified.
149
+
150
+ // Case 1:
151
+ if ( $absolute_used == 0 && $percent_used == 0 ) {
152
+ $increment = $width - $min_width;
153
+
154
+ foreach (array_keys($columns) as $i)
155
+ $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment * ($columns[$i]["max-width"] / $max_width));
156
+ return;
157
+ }
158
+
159
+
160
+ // Case 2
161
+ if ( $absolute_used > 0 && $percent_used == 0 ) {
162
+
163
+ if ( count($auto) > 0 )
164
+ $increment = ($width - $auto_min - $absolute_used) / count($auto);
165
+
166
+ // Use the absolutely specified width or the increment
167
+ foreach (array_keys($columns) as $i) {
168
+
169
+ if ( $columns[$i]["absolute"] > 0 && count($auto) )
170
+ $cellmap->set_column_width($i, $columns[$i]["min-width"]);
171
+ else if ( count($auto) )
172
+ $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
173
+ else {
174
+ // All absolute columns
175
+ $increment = ($width - $absolute_used) * $columns[$i]["absolute"] / $absolute_used;
176
+
177
+ $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
178
+ }
179
+
180
+ }
181
+ return;
182
+ }
183
+
184
+
185
+ // Case 3:
186
+ if ( $absolute_used == 0 && $percent_used > 0 ) {
187
+
188
+ $scale = null;
189
+ $remaining = null;
190
+
191
+ // Scale percent values if the total percentage is > 100, or if all
192
+ // values are specified as percentages.
193
+ if ( $percent_used > 100 || count($auto) == 0)
194
+ $scale = 100 / $percent_used;
195
+ else
196
+ $scale = 1;
197
+
198
+ // Account for the minimum space used by the unassigned auto columns
199
+ $used_width = $auto_min;
200
+
201
+ foreach ($percent as $i) {
202
+ $columns[$i]["percent"] *= $scale;
203
+
204
+ $slack = $width - $used_width;
205
+
206
+ $w = min($columns[$i]["percent"] * $width/100, $slack);
207
+
208
+ if ( $w < $columns[$i]["min-width"] )
209
+ $w = $columns[$i]["min-width"];
210
+
211
+ $cellmap->set_column_width($i, $w);
212
+ $used_width += $w;
213
+
214
+ }
215
+
216
+ // This works because $used_width includes the min-width of each
217
+ // unassigned column
218
+ if ( count($auto) > 0 ) {
219
+ $increment = ($width - $used_width) / count($auto);
220
+
221
+ foreach ($auto as $i)
222
+ $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
223
+
224
+ }
225
+ return;
226
+ }
227
+
228
+ // Case 4:
229
+
230
+ // First-come, first served
231
+ if ( $absolute_used > 0 && $percent_used > 0 ) {
232
+
233
+ $used_width = $auto_min;
234
+
235
+ foreach ($absolute as $i) {
236
+ $cellmap->set_column_width($i, $columns[$i]["min-width"]);
237
+ $used_width += $columns[$i]["min-width"];
238
+ }
239
+
240
+ // Scale percent values if the total percentage is > 100 or there
241
+ // are no auto values to take up slack
242
+ if ( $percent_used > 100 || count($auto) == 0 )
243
+ $scale = 100 / $percent_used;
244
+ else
245
+ $scale = 1;
246
+
247
+ $remaining_width = $width - $used_width;
248
+
249
+ foreach ($percent as $i) {
250
+ $slack = $remaining_width - $used_width;
251
+
252
+ $columns[$i]["percent"] *= $scale;
253
+ $w = min($columns[$i]["percent"] * $remaining_width / 100, $slack);
254
+
255
+ if ( $w < $columns[$i]["min-width"] )
256
+ $w = $columns[$i]["min-width"];
257
+
258
+ $columns[$i]["used-width"] = $w;
259
+ $used_width += $w;
260
+ }
261
+
262
+ if ( count($auto) > 0 ) {
263
+ $increment = ($width - $used_width) / count($auto);
264
+
265
+ foreach ($auto as $i)
266
+ $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
267
+
268
+ }
269
+
270
+ return;
271
+ }
272
+
273
+
274
+ } else { // we are over constrained
275
+
276
+ // Each column gets its minimum width
277
+ foreach (array_keys($columns) as $i)
278
+ $cellmap->set_column_width($i, $columns[$i]["min-width"]);
279
+
280
+ }
281
+ }
282
+
283
+ //........................................................................
284
+
285
+ // Determine the frame's height based on min/max height
286
+ protected function _calculate_height() {
287
+
288
+ $style = $this->_frame->get_style();
289
+ $height = $style->height;
290
+
291
+ $cellmap = $this->_frame->get_cellmap();
292
+ $cellmap->assign_frame_heights();
293
+ $rows = $cellmap->get_rows();
294
+
295
+ // Determine our content height
296
+ $content_height = 0;
297
+ foreach ( $rows as $r )
298
+ $content_height += $r["height"];
299
+
300
+ $cb = $this->_frame->get_containing_block();
301
+
302
+ if ( !($style->overflow === "visible" ||
303
+ ($style->overflow === "hidden" && $height === "auto")) ) {
304
+
305
+ // Only handle min/max height if the height is independent of the frame's content
306
+
307
+ $min_height = $style->min_height;
308
+ $max_height = $style->max_height;
309
+
310
+ if ( isset($cb["h"]) ) {
311
+ $min_height = $style->length_in_pt($min_height, $cb["h"]);
312
+ $max_height = $style->length_in_pt($max_height, $cb["h"]);
313
+
314
+ } else if ( isset($cb["w"]) ) {
315
+
316
+ if ( mb_strpos($min_height, "%") !== false )
317
+ $min_height = 0;
318
+ else
319
+ $min_height = $style->length_in_pt($min_height, $cb["w"]);
320
+
321
+ if ( mb_strpos($max_height, "%") !== false )
322
+ $max_height = "none";
323
+ else
324
+ $max_height = $style->length_in_pt($max_height, $cb["w"]);
325
+ }
326
+
327
+ if ( $max_height !== "none" && $min_height > $max_height )
328
+ // Swap 'em
329
+ list($max_height, $min_height) = array($min_height, $max_height);
330
+
331
+ if ( $max_height !== "none" && $height > $max_height )
332
+ $height = $max_height;
333
+
334
+ if ( $height < $min_height )
335
+ $height = $min_height;
336
+
337
+ } else {
338
+
339
+ // Use the content height or the height value, whichever is greater
340
+ if ( $height !== "auto" ) {
341
+ $height = $style->length_in_pt($height, $cb["h"]);
342
+
343
+ if ( $height <= $content_height )
344
+ $height = $content_height;
345
+ else
346
+ $cellmap->set_frame_heights($height,$content_height);
347
+
348
+ } else
349
+ $height = $content_height;
350
+
351
+ }
352
+
353
+ return $height;
354
+
355
+ }
356
+ //........................................................................
357
+
358
+ function reflow(Frame_Decorator $block = null) {
359
+ /**
360
+ * @var Table_Frame_Decorator
361
+ */
362
+ $frame = $this->_frame;
363
+
364
+ // Check if a page break is forced
365
+ $page = $frame->get_root();
366
+ $page->check_forced_page_break($frame);
367
+
368
+ // Bail if the page is full
369
+ if ( $page->is_full() )
370
+ return;
371
+
372
+ // Let the page know that we're reflowing a table so that splits
373
+ // are suppressed (simply setting page-break-inside: avoid won't
374
+ // work because we may have an arbitrary number of block elements
375
+ // inside tds.)
376
+ $page->table_reflow_start();
377
+
378
+ // Collapse vertical margins, if required
379
+ $this->_collapse_margins();
380
+
381
+ $frame->position();
382
+
383
+ // Table layout algorithm:
384
+ // http://www.w3.org/TR/CSS21/tables.html#auto-table-layout
385
+
386
+ if ( is_null($this->_state) )
387
+ $this->get_min_max_width();
388
+
389
+ $cb = $frame->get_containing_block();
390
+ $style = $frame->get_style();
391
+
392
+ // This is slightly inexact, but should be okay. Add half the
393
+ // border-spacing to the table as padding. The other half is added to
394
+ // the cells themselves.
395
+ if ( $style->border_collapse === "separate" ) {
396
+ list($h, $v) = $style->border_spacing;
397
+
398
+ $v = $style->length_in_pt($v) / 2;
399
+ $h = $style->length_in_pt($h) / 2;
400
+
401
+ $style->padding_left = $style->length_in_pt($style->padding_left, $cb["w"]) + $h;
402
+ $style->padding_right = $style->length_in_pt($style->padding_right, $cb["w"]) + $h;
403
+ $style->padding_top = $style->length_in_pt($style->padding_top, $cb["h"]) + $v;
404
+ $style->padding_bottom = $style->length_in_pt($style->padding_bottom, $cb["h"]) + $v;
405
+
406
+ }
407
+
408
+ $this->_assign_widths();
409
+
410
+ // Adjust left & right margins, if they are auto
411
+ $width = $style->width;
412
+ $left = $style->margin_left;
413
+ $right = $style->margin_right;
414
+
415
+ $diff = $cb["w"] - $width;
416
+
417
+ if ( $left === "auto" && $right === "auto" ) {
418
+ if ( $diff < 0 ) {
419
+ $left = 0;
420
+ $right = $diff;
421
+ }
422
+ else {
423
+ $left = $right = $diff / 2;
424
+ }
425
+
426
+ $style->margin_left = "$left pt";
427
+ $style->margin_right = "$right pt";
428
+
429
+ } else {
430
+ if ( $left === "auto" ) {
431
+ $left = $style->length_in_pt($cb["w"] - $right - $width, $cb["w"]);
432
+ }
433
+ if ( $right === "auto" ) {
434
+ $left = $style->length_in_pt($left, $cb["w"]);
435
+ }
436
+ }
437
+
438
+ list($x, $y) = $frame->get_position();
439
+
440
+ // Determine the content edge
441
+ $content_x = $x + $left + $style->length_in_pt(array($style->padding_left,
442
+ $style->border_left_width), $cb["w"]);
443
+ $content_y = $y + $style->length_in_pt(array($style->margin_top,
444
+ $style->border_top_width,
445
+ $style->padding_top), $cb["h"]);
446
+
447
+ if ( isset($cb["h"]) )
448
+ $h = $cb["h"];
449
+ else
450
+ $h = null;
451
+
452
+ $cellmap = $frame->get_cellmap();
453
+ $col =& $cellmap->get_column(0);
454
+ $col["x"] = $content_x;
455
+
456
+ $row =& $cellmap->get_row(0);
457
+ $row["y"] = $content_y;
458
+
459
+ $cellmap->assign_x_positions();
460
+
461
+ // Set the containing block of each child & reflow
462
+ foreach ( $frame->get_children() as $child ) {
463
+
464
+ // Bail if the page is full
465
+ if ( !$page->in_nested_table() && $page->is_full() )
466
+ break;
467
+
468
+ $child->set_containing_block($content_x, $content_y, $width, $h);
469
+ $child->reflow();
470
+
471
+ if ( !$page->in_nested_table() )
472
+ // Check if a split has occured
473
+ $page->check_page_break($child);
474
+
475
+ }
476
+
477
+ // Assign heights to our cells:
478
+ $style->height = $this->_calculate_height();
479
+
480
+ if ( $style->border_collapse === "collapse" ) {
481
+ // Unset our borders because our cells are now using them
482
+ $style->border_style = "none";
483
+ }
484
+
485
+ $page->table_reflow_end();
486
+
487
+ // Debugging:
488
+ //echo ($this->_frame->get_cellmap());
489
+
490
+ if ( $block && $style->float === "none" && $frame->is_in_flow() ) {
491
+ $block->add_frame_to_line($frame);
492
+ $block->add_line();
493
+ }
494
+ }
495
+
496
+ //........................................................................
497
+
498
+ function get_min_max_width() {
499
+
500
+ if ( !is_null($this->_min_max_cache) )
501
+ return $this->_min_max_cache;
502
+
503
+ $style = $this->_frame->get_style();
504
+
505
+ $this->_frame->normalise();
506
+
507
+ // Add the cells to the cellmap (this will calcluate column widths as
508
+ // frames are added)
509
+ $this->_frame->get_cellmap()->add_frame($this->_frame);
510
+
511
+ // Find the min/max width of the table and sort the columns into
512
+ // absolute/percent/auto arrays
513
+ $this->_state = array();
514
+ $this->_state["min_width"] = 0;
515
+ $this->_state["max_width"] = 0;
516
+
517
+ $this->_state["percent_used"] = 0;
518
+ $this->_state["absolute_used"] = 0;
519
+ $this->_state["auto_min"] = 0;
520
+
521
+ $this->_state["absolute"] = array();
522
+ $this->_state["percent"] = array();
523
+ $this->_state["auto"] = array();
524
+
525
+ $columns =& $this->_frame->get_cellmap()->get_columns();
526
+ foreach (array_keys($columns) as $i) {
527
+ $this->_state["min_width"] += $columns[$i]["min-width"];
528
+ $this->_state["max_width"] += $columns[$i]["max-width"];
529
+
530
+ if ( $columns[$i]["absolute"] > 0 ) {
531
+ $this->_state["absolute"][] = $i;
532
+ $this->_state["absolute_used"] += $columns[$i]["absolute"];
533
+
534
+ } else if ( $columns[$i]["percent"] > 0 ) {
535
+ $this->_state["percent"][] = $i;
536
+ $this->_state["percent_used"] += $columns[$i]["percent"];
537
+
538
+ } else {
539
+ $this->_state["auto"][] = $i;
540
+ $this->_state["auto_min"] += $columns[$i]["min-width"];
541
+ }
542
+ }
543
+
544
+ // Account for margins & padding
545
+ $dims = array($style->border_left_width,
546
+ $style->border_right_width,
547
+ $style->padding_left,
548
+ $style->padding_right,
549
+ $style->margin_left,
550
+ $style->margin_right);
551
+
552
+ if ( $style->border_collapse !== "collapse" )
553
+ list($dims[]) = $style->border_spacing;
554
+
555
+ $delta = $style->length_in_pt($dims, $this->_frame->get_containing_block("w"));
556
+
557
+ $this->_state["min_width"] += $delta;
558
+ $this->_state["max_width"] += $delta;
559
+
560
+ return $this->_min_max_cache = array(
561
+ $this->_state["min_width"],
562
+ $this->_state["max_width"],
563
+ "min" => $this->_state["min_width"],
564
+ "max" => $this->_state["max_width"],
565
+ );
566
+ }
567
+ }
dompdf/include/table_row_frame_decorator.cls.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_row_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Decorates Frames for table row layout
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Row_Frame_Decorator extends Frame_Decorator {
17
+
18
+ // protected members
19
+
20
+ function __construct(Frame $frame, DOMPDF $dompdf) {
21
+ parent::__construct($frame, $dompdf);
22
+ }
23
+
24
+ //........................................................................
25
+
26
+ /**
27
+ * Remove all non table-cell frames from this row and move them after
28
+ * the table.
29
+ */
30
+ function normalise() {
31
+
32
+ // Find our table parent
33
+ $p = Table_Frame_Decorator::find_parent_table($this);
34
+
35
+ $erroneous_frames = array();
36
+ foreach ($this->get_children() as $child) {
37
+ $display = $child->get_style()->display;
38
+
39
+ if ( $display !== "table-cell" )
40
+ $erroneous_frames[] = $child;
41
+ }
42
+
43
+ // dump the extra nodes after the table.
44
+ foreach ($erroneous_frames as $frame)
45
+ $p->move_after($frame);
46
+ }
47
+
48
+
49
+ }
dompdf/include/table_row_frame_reflower.cls.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_row_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Reflows table rows
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Row_Frame_Reflower extends Frame_Reflower {
17
+
18
+
19
+ function __construct(Table_Row_Frame_Decorator $frame) {
20
+ parent::__construct($frame);
21
+ }
22
+
23
+ //........................................................................
24
+
25
+ function reflow(Frame_Decorator $block = null) {
26
+ $page = $this->_frame->get_root();
27
+
28
+ if ( $page->is_full() )
29
+ return;
30
+
31
+ $this->_frame->position();
32
+ $style = $this->_frame->get_style();
33
+ $cb = $this->_frame->get_containing_block();
34
+
35
+ foreach ($this->_frame->get_children() as $child) {
36
+
37
+ if ( $page->is_full() )
38
+ return;
39
+
40
+ $child->set_containing_block($cb);
41
+ $child->reflow();
42
+
43
+ }
44
+
45
+ if ( $page->is_full() )
46
+ return;
47
+
48
+ $table = Table_Frame_Decorator::find_parent_table($this->_frame);
49
+ $cellmap = $table->get_cellmap();
50
+ $style->width = $cellmap->get_frame_width($this->_frame);
51
+ $style->height = $cellmap->get_frame_height($this->_frame);
52
+
53
+ $this->_frame->set_position($cellmap->get_frame_position($this->_frame));
54
+
55
+ }
56
+
57
+ //........................................................................
58
+
59
+ function get_min_max_width() {
60
+ throw new DOMPDF_Exception("Min/max width is undefined for table rows");
61
+ }
62
+ }
dompdf/include/table_row_group_frame_decorator.cls.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_row_group_frame_decorator.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Table row group decorator
12
+ *
13
+ * Overrides split() method for tbody, thead & tfoot elements
14
+ *
15
+ * @access private
16
+ * @package dompdf
17
+ */
18
+ class Table_Row_Group_Frame_Decorator extends Frame_Decorator {
19
+
20
+ /**
21
+ * Class constructor
22
+ *
23
+ * @param Frame $frame Frame to decorate
24
+ * @param DOMPDF $dompdf Current dompdf instance
25
+ */
26
+ function __construct(Frame $frame, DOMPDF $dompdf) {
27
+ parent::__construct($frame, $dompdf);
28
+ }
29
+
30
+ /**
31
+ * Override split() to remove all child rows and this element from the cellmap
32
+ *
33
+ * @param Frame $child
34
+ */
35
+ function split($child = null, $force_pagebreak = false) {
36
+
37
+ if ( is_null($child) ) {
38
+ parent::split();
39
+ return;
40
+ }
41
+
42
+
43
+ // Remove child & all subsequent rows from the cellmap
44
+ $cellmap = $this->get_parent()->get_cellmap();
45
+ $iter = $child;
46
+
47
+ while ( $iter ) {
48
+ $cellmap->remove_row($iter);
49
+ $iter = $iter->get_next_sibling();
50
+ }
51
+
52
+ // If we are splitting at the first child remove the
53
+ // table-row-group from the cellmap as well
54
+ if ( $child === $this->get_first_child() ) {
55
+ $cellmap->remove_row_group($this);
56
+ parent::split();
57
+ return;
58
+ }
59
+
60
+ $cellmap->update_row_group($this, $child->get_prev_sibling());
61
+ parent::split($child);
62
+
63
+ }
64
+ }
65
+
dompdf/include/table_row_group_frame_reflower.cls.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_row_group_frame_reflower.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Reflows table row groups (e.g. tbody tags)
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Row_Group_Frame_Reflower extends Frame_Reflower {
17
+
18
+ function __construct($frame) {
19
+ parent::__construct($frame);
20
+ }
21
+
22
+ function reflow(Frame_Decorator $block = null) {
23
+ $page = $this->_frame->get_root();
24
+
25
+ $style = $this->_frame->get_style();
26
+
27
+ // Our width is equal to the width of our parent table
28
+ $table = Table_Frame_Decorator::find_parent_table($this->_frame);
29
+
30
+ $cb = $this->_frame->get_containing_block();
31
+
32
+ foreach ( $this->_frame->get_children() as $child) {
33
+ // Bail if the page is full
34
+ if ( $page->is_full() )
35
+ return;
36
+
37
+ $child->set_containing_block($cb["x"], $cb["y"], $cb["w"], $cb["h"]);
38
+ $child->reflow();
39
+
40
+ // Check if a split has occured
41
+ $page->check_page_break($child);
42
+
43
+ }
44
+
45
+ if ( $page->is_full() )
46
+ return;
47
+
48
+ $cellmap = $table->get_cellmap();
49
+ $style->width = $cellmap->get_frame_width($this->_frame);
50
+ $style->height = $cellmap->get_frame_height($this->_frame);
51
+
52
+ $this->_frame->set_position($cellmap->get_frame_position($this->_frame));
53
+
54
+ if ( $table->get_style()->border_collapse === "collapse" )
55
+ // Unset our borders because our cells are now using them
56
+ $style->border_style = "none";
57
+
58
+ }
59
+
60
+ }
dompdf/include/table_row_group_renderer.cls.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_row_group_renderer.cls.php 449 2011-11-13 13:07:48Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Renders block frames
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Row_Group_Renderer extends Block_Renderer {
17
+
18
+ //........................................................................
19
+
20
+ function render(Frame $frame) {
21
+ $style = $frame->get_style();
22
+
23
+ $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
24
+
25
+ $this->_render_border($frame);
26
+ $this->_render_outline($frame);
27
+
28
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) {
29
+ $this->_debug_layout($frame->get_border_box(), "red");
30
+ if (DEBUG_LAYOUT_PADDINGBOX) {
31
+ $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5));
32
+ }
33
+ }
34
+
35
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES && $frame->get_decorator()) {
36
+ foreach ($frame->get_decorator()->get_line_boxes() as $line) {
37
+ $frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange");
38
+ }
39
+ }
40
+ }
41
+ }
dompdf/include/table_row_positioner.cls.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: table_row_positioner.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ /**
11
+ * Positions table rows
12
+ *
13
+ * @access private
14
+ * @package dompdf
15
+ */
16
+ class Table_Row_Positioner extends Positioner {
17
+
18
+ function __construct(Frame_Decorator $frame) { parent::__construct($frame); }
19
+
20
+ //........................................................................
21
+
22
+ function position() {
23
+
24
+ $cb = $this->_frame->get_containing_block();
25
+ $p = $this->_frame->get_prev_sibling();
26
+
27
+ if ( $p )
28
+ $y = $p->get_position("y") + $p->get_margin_height();
29
+
30
+ else
31
+ $y = $cb["y"];
32
+
33
+ $this->_frame->set_position($cb["x"], $y);
34
+
35
+ }
36
+ }
dompdf/include/tcpdf_adapter.cls.php ADDED
@@ -0,0 +1,466 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7
+ * @version $Id: tcpdf_adapter.cls.php 448 2011-11-13 13:00:03Z fabien.menager $
8
+ */
9
+
10
+ require_once(DOMPDF_LIB_DIR . '/tcpdf/tcpdf.php');
11
+
12
+ /**
13
+ * TCPDF PDF Rendering interface
14
+ *
15
+ * TCPDF_Adapter provides a simple, stateless interface to TCPDF.
16
+ *
17
+ * Unless otherwise mentioned, all dimensions are in points (1/72 in).
18
+ * The coordinate origin is in the top left corner and y values
19
+ * increase downwards.
20
+ *
21
+ * See {@link http://tcpdf.sourceforge.net} for more information on
22
+ * the underlying TCPDF class.
23
+ *
24
+ * @package dompdf
25
+ */
26
+ class TCPDF_Adapter implements Canvas {
27
+
28
+ /**
29
+ * Dimensions of paper sizes in points
30
+ *
31
+ * @var array;
32
+ */
33
+ static public $PAPER_SIZES = array(); // Set to
34
+ // CPDF_Adapter::$PAPER_SIZES below.
35
+
36
+
37
+ /**
38
+ * Instance of the TCPDF class
39
+ *
40
+ * @var TCPDF
41
+ */
42
+ private $_pdf;
43
+
44
+ /**
45
+ * PDF width in points
46
+ *
47
+ * @var float
48
+ */
49
+ private $_width;
50
+
51
+ /**
52
+ * PDF height in points
53
+ *
54
+ * @var float
55
+ */
56
+ private $_height;
57
+
58
+ /**
59
+ * Last fill colour used
60
+ *
61
+ * @var array
62
+ */
63
+ private $_last_fill_color;
64
+
65
+ /**
66
+ * Last stroke colour used
67
+ *
68
+ * @var array
69
+ */
70
+ private $_last_stroke_color;
71
+
72
+ /**
73
+ * Last line width used
74
+ *
75
+ * @var float
76
+ */
77
+ private $_last_line_width;
78
+
79
+ /**
80
+ * Total number of pages
81
+ *
82
+ * @var int
83
+ */
84
+ private $_page_count;
85
+
86
+ /**
87
+ * Text to display on every page
88
+ *
89
+ * @var array
90
+ */
91
+ private $_page_text;
92
+
93
+ /**
94
+ * Array of pages for accessing after initial rendering is complete
95
+ *
96
+ * @var array
97
+ */
98
+ private $_pages;
99
+
100
+ /**
101
+ * Class constructor
102
+ *
103
+ * @param mixed $paper The size of paper to use either a string (see {@link CPDF_Adapter::$PAPER_SIZES}) or
104
+ * an array(xmin,ymin,xmax,ymax)
105
+ * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
106
+ */
107
+ function __construct($paper = "letter", $orientation = "portrait") {
108
+
109
+ if ( is_array($paper) )
110
+ $size = $paper;
111
+ else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) )
112
+ $size = self::$PAPER_SIZE[$paper];
113
+ else
114
+ $size = self::$PAPER_SIZE["letter"];
115
+
116
+ if ( mb_strtolower($orientation) === "landscape" ) {
117
+ list($size[2], $size[3]) = array($size[3], $size[2]);
118
+ }
119
+
120
+ $this->_width = $size[2] - $size[0];
121
+ $this->_height = $size[3] - $size[1];
122
+
123
+ $this->_pdf = new TCPDF("P", "pt", array($this->_width, $this->_height));
124
+ $this->_pdf->Setcreator("DOMPDF Converter");
125
+
126
+ $this->_pdf->AddPage();
127
+
128
+ $this->_page_number = $this->_page_count = 1;
129
+ $this->_page_text = array();
130
+
131
+ $this->_last_fill_color =
132
+ $this->_last_stroke_color =
133
+ $this->_last_line_width = null;
134
+
135
+ }
136
+
137
+ /**
138
+ * Remaps y coords from 4th to 1st quadrant
139
+ *
140
+ * @param float $y
141
+ * @return float
142
+ */
143
+ protected function y($y) { return $this->_height - $y; }
144
+
145
+ /**
146
+ * Sets the stroke colour
147
+ *
148
+ * @param array $color
149
+ */
150
+ protected function _set_stroke_colour($colour) {
151
+ $colour[0] = round(255 * $colour[0]);
152
+ $colour[1] = round(255 * $colour[1]);
153
+ $colour[2] = round(255 * $colour[2]);
154
+
155
+ if ( is_null($this->_last_stroke_color) || $color != $this->_last_stroke_color ) {
156
+ $this->_pdf->SetDrawColor($color[0],$color[1],$color[2]);
157
+ $this->_last_stroke_color = $color;
158
+ }
159
+
160
+ }
161
+
162
+ /**
163
+ * Sets the fill colour
164
+ *
165
+ * @param array $color
166
+ */
167
+ protected function _set_fill_colour($colour) {
168
+ $colour[0] = round(255 * $colour[0]);
169
+ $colour[1] = round(255 * $colour[1]);
170
+ $colour[2] = round(255 * $colour[2]);
171
+
172
+ if ( is_null($this->_last_fill_color) || $color != $this->_last_fill_color ) {
173
+ $this->_pdf->SetDrawColor($color[0],$color[1],$color[2]);
174
+ $this->_last_fill_color = $color;
175
+ }
176
+
177
+ }
178
+
179
+ /**
180
+ * Return the TCPDF instance
181
+ *
182
+ * @return TCPDF
183
+ */
184
+ function get_tcpdf() { return $this->_pdf; }
185
+
186
+ /**
187
+ * Returns the current page number
188
+ *
189
+ * @return int
190
+ */
191
+ function get_page_number() {
192
+ return $this->_page_number;
193
+ }
194
+
195
+ /**
196
+ * Returns the total number of pages
197
+ *
198
+ * @return int
199
+ */
200
+ function get_page_count() {
201
+ return $this->_page_count;
202
+ }
203
+
204
+ /**
205
+ * Sets the total number of pages
206
+ *
207
+ * @param int $count
208
+ */
209
+ function set_page_count($count) {
210
+ $this->_page_count = (int)$count;
211
+ }
212
+
213
+ /**
214
+ * Draws a line from x1,y1 to x2,y2
215
+ *
216
+ * See {@link Style::munge_colour()} for the format of the colour array.
217
+ * See {@link Cpdf::setLineStyle()} for a description of the format of the
218
+ * $style parameter (aka dash).
219
+ *
220
+ * @param float $x1
221
+ * @param float $y1
222
+ * @param float $x2
223
+ * @param float $y2
224
+ * @param array $color
225
+ * @param float $width
226
+ * @param array $style
227
+ */
228
+ function line($x1, $y1, $x2, $y2, $color, $width, $style = null) {
229
+
230
+ if ( is_null($this->_last_line_width) || $width != $this->_last_line_width ) {
231
+ $this->_pdf->SetLineWidth($width);
232
+ $this->_last_line_width = $width;
233
+ }
234
+
235
+ $this->_set_stroke_colour($color);
236
+
237
+ // FIXME: ugh, need to handle different styles here
238
+ $this->_pdf->line($x1, $y1, $x2, $y2);
239
+ }
240
+
241
+ /**
242
+ * Draws a rectangle at x1,y1 with width w and height h
243
+ *
244
+ * See {@link Style::munge_colour()} for the format of the colour array.
245
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
246
+ * parameter (aka dash)
247
+ *
248
+ * @param float $x1
249
+ * @param float $y1
250
+ * @param float $w
251
+ * @param float $h
252
+ * @param array $color
253
+ * @param float $width
254
+ * @param array $style
255
+ */
256
+ function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) {
257
+
258
+ if ( is_null($this->_last_line_width) || $width != $this->_last_line_width ) {
259
+ $this->_pdf->SetLineWidth($width);
260
+ $this->_last_line_width = $width;
261
+ }
262
+
263
+ $this->_set_stroke_colour($color);
264
+
265
+ // FIXME: ugh, need to handle styles here
266
+ $this->_pdf->rect($x1, $y1, $w, $h);
267
+
268
+ }
269
+
270
+ /**
271
+ * Draws a filled rectangle at x1,y1 with width w and height h
272
+ *
273
+ * See {@link Style::munge_colour()} for the format of the colour array.
274
+ *
275
+ * @param float $x1
276
+ * @param float $y1
277
+ * @param float $w
278
+ * @param float $h
279
+ * @param array $color
280
+ */
281
+ function filled_rectangle($x1, $y1, $w, $h, $color) {
282
+
283
+ $this->_set_fill_colour($color);
284
+
285
+ // FIXME: ugh, need to handle styles here
286
+ $this->_pdf->rect($x1, $y1, $w, $h, "F");
287
+ }
288
+
289
+ /**
290
+ * Draws a polygon
291
+ *
292
+ * The polygon is formed by joining all the points stored in the $points
293
+ * array. $points has the following structure:
294
+ * <code>
295
+ * array(0 => x1,
296
+ * 1 => y1,
297
+ * 2 => x2,
298
+ * 3 => y2,
299
+ * ...
300
+ * );
301
+ * </code>
302
+ *
303
+ * See {@link Style::munge_colour()} for the format of the colour array.
304
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
305
+ * parameter (aka dash)
306
+ *
307
+ * @param array $points
308
+ * @param array $color
309
+ * @param float $width
310
+ * @param array $style
311
+ * @param bool $fill Fills the polygon if true
312
+ */
313
+ function polygon($points, $color, $width = null, $style = null, $fill = false) {
314
+ // FIXME
315
+ }
316
+
317
+ /**
318
+ * Draws a circle at $x,$y with radius $r
319
+ *
320
+ * See {@link Style::munge_colour()} for the format of the colour array.
321
+ * See {@link Cpdf::setLineStyle()} for a description of the $style
322
+ * parameter (aka dash)
323
+ *
324
+ * @param float $x
325
+ * @param float $y
326
+ * @param float $r
327
+ * @param array $color
328
+ * @param float $width
329
+ * @param array $style
330
+ * @param bool $fill Fills the circle if true
331
+ */
332
+ function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) {
333
+ // FIXME
334
+ }
335
+
336
+ /**
337
+ * Add an image to the pdf.
338
+ *
339
+ * The image is placed at the specified x and y coordinates with the
340
+ * given width and height.
341
+ *
342
+ * @param string $img_url the path to the image
343
+ * @param string $img_type the type (e.g. extension) of the image
344
+ * @param float $x x position
345
+ * @param float $y y position
346
+ * @param int $w width (in pixels)
347
+ * @param int $h height (in pixels)
348
+ */
349
+ function image($img_url, $img_type, $x, $y, $w, $h) {
350
+ // FIXME
351
+ }
352
+
353
+ /**
354
+ * Writes text at the specified x and y coordinates
355
+ *
356
+ * See {@link Style::munge_colour()} for the format of the colour array.
357
+ *
358
+ * @param float $x
359
+ * @param float $y
360
+ * @param string $text the text to write
361
+ * @param string $font the font file to use
362
+ * @param float $size the font size, in points
363
+ * @param array $color
364
+ * @param float $adjust word spacing adjustment
365
+ */
366
+ function text($x, $y, $text, $font, $size, $color = array(0,0,0), $adjust = 0) {
367
+ // FIXME
368
+ }
369
+
370
+ function javascript($code) {
371
+ // FIXME
372
+ }
373
+
374
+ /**
375
+ * Add a named destination (similar to <a name="foo">...</a> in html)
376
+ *
377
+ * @param string $anchorname The name of the named destination
378
+ */
379
+ function add_named_dest($anchorname) {
380
+ // FIXME
381
+ }
382
+
383
+ /**
384
+ * Add a link to the pdf
385
+ *
386
+ * @param string $url The url to link to
387
+ * @param float $x The x position of the link
388
+ * @param float $y The y position of the link
389
+ * @param float $width The width of the link
390
+ * @param float $height The height of the link
391
+ */
392
+ function add_link($url, $x, $y, $width, $height) {
393
+ // FIXME
394
+ }
395
+
396
+ /**
397
+ * Add meta information to the PDF
398
+ *
399
+ * @param string $label label of the value (Creator, Producer, etc.)
400
+ * @param string $value the text to set
401
+ */
402
+ function add_info($label, $value) {
403
+ $method = "Set$label";
404
+ if ( in_array("Title", "Author", "Keywords", "Subject") && method_exists($this->_pdf, $method) ) {
405
+ $this->_pdf->$method($value);
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Calculates text size, in points
411
+ *
412
+ * @param string $text the text to be sized
413
+ * @param string $font the desired font
414
+ * @param float $size the desired font size
415
+ * @param float $spacing word spacing, if any
416
+ * @return float
417
+ */
418
+ function get_text_width($text, $font, $size, $spacing = 0) {
419
+ // FIXME
420
+ }
421
+
422
+ /**
423
+ * Calculates font height, in points
424
+ *
425
+ * @param string $font
426
+ * @param float $size
427
+ * @return float
428
+ */
429
+ function get_font_height($font, $size) {
430
+ // FIXME
431
+ }
432
+
433
+
434
+ /**
435
+ * Starts a new page
436
+ *
437
+ * Subsequent drawing operations will appear on the new page.
438
+ */
439
+ function new_page() {
440
+ // FIXME
441
+ }
442
+
443
+ /**
444
+ * Streams the PDF directly to the browser
445
+ *
446
+ * @param string $filename the name of the PDF file
447
+ * @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
448
+ */
449
+ function stream($filename, $options = null) {
450
+ // FIXME
451
+ }
452
+
453
+ /**
454
+ * Returns the PDF as a string
455
+ *
456
+ * @param array $options associative array: 'compress' => 1 or 0
457
+ * @return string
458
+ */
459
+ function output($options = null) {
460
+ // FIXME
461
+ }
462
+
463
+ }
464
+
465
+ // Workaround for idiotic limitation on statics...
466
+ PDFLib_Adapter::$PAPER_SIZES = CPDF_Adapter::$PAPER_SIZES;
dompdf/include/text_frame_decorator.cls.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Brian Sweeney <eclecticgeek@gmail.com>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: text_frame_decorator.cls.php 459 2012-01-25 21:38:50Z fabien.menager $
10
+ */
11
+
12
+ /**
13
+ * Decorates Frame objects for text layout
14
+ *
15
+ * @access private
16
+ * @package dompdf
17
+ */
18
+ class Text_Frame_Decorator extends Frame_Decorator {
19
+
20
+ // protected members
21
+ protected $_text_spacing;
22
+
23
+ // buggy DOMText::splitText (PHP < 5.2.7)
24
+ public static $_buggy_splittext;
25
+
26
+ function __construct(Frame $frame, DOMPDF $dompdf) {
27
+ if ( !$frame->is_text_node() )
28
+ throw new DOMPDF_Exception("Text_Decorator can only be applied to #text nodes.");
29
+
30
+ parent::__construct($frame, $dompdf);
31
+ $this->_text_spacing = null;
32
+ }
33
+
34
+ //........................................................................
35
+
36
+ function reset() {
37
+ parent::reset();
38
+ $this->_text_spacing = null;
39
+ }
40
+
41
+ //........................................................................
42
+
43
+ // Accessor methods
44
+ function get_text_spacing() { return $this->_text_spacing; }
45
+
46
+ function get_text() {
47
+ // FIXME: this should be in a child class (and is incorrect)
48
+ // if ( $this->_frame->get_style()->content !== "normal" ) {
49
+ // $this->_frame->get_node()->data = $this->_frame->get_style()->content;
50
+ // $this->_frame->get_style()->content = "normal";
51
+ // }
52
+
53
+ // pre_r("---");
54
+ // $style = $this->_frame->get_style();
55
+ // var_dump($text = $this->_frame->get_node()->data);
56
+ // var_dump($asc = utf8_decode($text));
57
+ // for ($i = 0; $i < strlen($asc); $i++)
58
+ // pre_r("$i: " . $asc[$i] . " - " . ord($asc[$i]));
59
+ // pre_r("width: " . Font_Metrics::get_text_width($text, $style->font_family, $style->font_size));
60
+
61
+ return $this->_frame->get_node()->data;
62
+ }
63
+
64
+ //........................................................................
65
+
66
+ // Vertical margins & padding do not apply to text frames
67
+
68
+ // http://www.w3.org/TR/CSS21/visudet.html#inline-non-replaced:
69
+ //
70
+ // The vertical padding, border and margin of an inline, non-replaced box
71
+ // start at the top and bottom of the content area, not the
72
+ // 'line-height'. But only the 'line-height' is used to calculate the
73
+ // height of the line box.
74
+ function get_margin_height() {
75
+ // This function is called in add_frame_to_line() and is used to
76
+ // determine the line height, so we actually want to return the
77
+ // 'line-height' property, not the actual margin box
78
+ $style = $this->get_style();
79
+ $font = $style->font_family;
80
+ $size = $style->font_size;
81
+
82
+ /*
83
+ pre_r('-----');
84
+ pre_r($style->line_height);
85
+ pre_r($style->font_size);
86
+ pre_r(Font_Metrics::get_font_height($font, $size));
87
+ pre_r(($style->line_height / $size) * Font_Metrics::get_font_height($font, $size));
88
+ */
89
+
90
+ return ($style->line_height / $size) * Font_Metrics::get_font_height($font, $size);
91
+
92
+ }
93
+
94
+ function get_padding_box() {
95
+ $pb = $this->_frame->get_padding_box();
96
+ $pb[3] = $pb["h"] = $this->_frame->get_style()->height;
97
+ return $pb;
98
+ }
99
+ //........................................................................
100
+
101
+ // Set method
102
+ function set_text_spacing($spacing) {
103
+ $style = $this->_frame->get_style();
104
+
105
+ $this->_text_spacing = $spacing;
106
+ $char_spacing = $style->length_in_pt($style->letter_spacing);
107
+
108
+ // Re-adjust our width to account for the change in spacing
109
+ $style->width = Font_Metrics::get_text_width($this->get_text(), $style->font_family, $style->font_size, $spacing, $char_spacing);
110
+ }
111
+
112
+ //........................................................................
113
+
114
+ // Recalculate the text width
115
+ function recalculate_width() {
116
+ $style = $this->get_style();
117
+ $text = $this->get_text();
118
+ $size = $style->font_size;
119
+ $font = $style->font_family;
120
+ $word_spacing = $style->length_in_pt($style->word_spacing);
121
+ $char_spacing = $style->length_in_pt($style->letter_spacing);
122
+
123
+ return $style->width = Font_Metrics::get_text_width($text, $font, $size, $word_spacing, $char_spacing);
124
+ }
125
+
126
+ //........................................................................
127
+
128
+ // Text manipulation methods
129
+
130
+ // split the text in this frame at the offset specified. The remaining
131
+ // text is added a sibling frame following this one and is returned.
132
+ function split_text($offset) {
133
+ if ( $offset == 0 )
134
+ return;
135
+
136
+ if ( self::$_buggy_splittext ) {
137
+ // workaround to solve DOMText::spliText() bug parsing multibyte strings
138
+ $node = $this->_frame->get_node();
139
+ $txt0 = $node->substringData(0, $offset);
140
+ $txt1 = $node->substringData($offset, mb_strlen($node->textContent)-1);
141
+
142
+ $node->replaceData(0, mb_strlen($node->textContent), $txt0);
143
+ $split = $node->parentNode->appendChild(new DOMText($txt1));
144
+ }
145
+ else {
146
+ $split = $this->_frame->get_node()->splitText($offset);
147
+ }
148
+
149
+ $deco = $this->copy($split);
150
+
151
+ $p = $this->get_parent();
152
+ $p->insert_child_after($deco, $this, false);
153
+
154
+ if ( $p instanceof Inline_Frame_Decorator )
155
+ $p->split($deco);
156
+
157
+ return $deco;
158
+ }
159
+
160
+ //........................................................................
161
+
162
+ function delete_text($offset, $count) {
163
+ $this->_frame->get_node()->deleteData($offset, $count);
164
+ }
165
+
166
+ //........................................................................
167
+
168
+ function set_text($text) {
169
+ $this->_frame->get_node()->data = $text;
170
+ }
171
+
172
+ }
173
+
174
+ Text_Frame_Decorator::$_buggy_splittext = PHP_VERSION_ID < 50207;
dompdf/include/text_frame_reflower.cls.php ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien M�nager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ * @version $Id: text_frame_reflower.cls.php 462 2012-01-29 22:44:23Z fabien.menager $
9
+ */
10
+
11
+ /**
12
+ * Reflows text frames.
13
+ *
14
+ * @access private
15
+ * @package dompdf
16
+ */
17
+ class Text_Frame_Reflower extends Frame_Reflower {
18
+
19
+ /**
20
+ * @var Block_Frame_Decorator
21
+ */
22
+ protected $_block_parent; // Nearest block-level ancestor
23
+
24
+ /**
25
+ * @var Text_Frame_Decorator
26
+ */
27
+ protected $_frame;
28
+
29
+ public static $_whitespace_pattern = "/[ \t\r\n\f]+/u";
30
+
31
+ function __construct(Text_Frame_Decorator $frame) { parent::__construct($frame); }
32
+
33
+ //........................................................................
34
+
35
+ protected function _collapse_white_space($text) {
36
+ //$text = $this->_frame->get_text();
37
+ // if ( $this->_block_parent->get_current_line_box->w == 0 )
38
+ // $text = ltrim($text, " \n\r\t");
39
+ return preg_replace(self::$_whitespace_pattern, " ", $text);
40
+ }
41
+
42
+ //........................................................................
43
+
44
+ protected function _line_break($text) {
45
+ $style = $this->_frame->get_style();
46
+ $size = $style->font_size;
47
+ $font = $style->font_family;
48
+ $current_line = $this->_block_parent->get_current_line_box();
49
+
50
+ // Determine the available width
51
+ $line_width = $this->_frame->get_containing_block("w");
52
+ $current_line_width = $current_line->left + $current_line->w + $current_line->right;
53
+
54
+ $available_width = $line_width - $current_line_width;
55
+
56
+ // split the text into words
57
+ $words = preg_split('/([\s-]+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
58
+ $wc = count($words);
59
+
60
+ // Account for word-spacing
61
+ $word_spacing = $style->length_in_pt($style->word_spacing);
62
+ $char_spacing = $style->length_in_pt($style->letter_spacing);
63
+
64
+ // Determine the frame width including margin, padding & border
65
+ $text_width = Font_Metrics::get_text_width($text, $font, $size, $word_spacing, $char_spacing);
66
+ $mbp_width =
67
+ $style->length_in_pt( array( $style->margin_left,
68
+ $style->border_left_width,
69
+ $style->padding_left,
70
+ $style->padding_right,
71
+ $style->border_right_width,
72
+ $style->margin_right), $line_width );
73
+
74
+ $frame_width = $text_width + $mbp_width;
75
+
76
+ // Debugging:
77
+ // pre_r("Text: '" . htmlspecialchars($text). "'");
78
+ // pre_r("width: " .$frame_width);
79
+ // pre_r("textwidth + delta: $text_width + $mbp_width");
80
+ // pre_r("font-size: $size");
81
+ // pre_r("cb[w]: " .$line_width);
82
+ // pre_r("available width: " . $available_width);
83
+ // pre_r("current line width: " . $current_line_width);
84
+
85
+ // pre_r($words);
86
+
87
+ if ( $frame_width <= $available_width )
88
+ return false;
89
+
90
+ // Determine the split point
91
+ $width = 0;
92
+ $str = "";
93
+ reset($words);
94
+
95
+ // @todo support <shy>, <wbr>
96
+ for ($i = 0; $i < $wc; $i += 2) {
97
+ $word = $words[$i] . (isset($words[$i+1]) ? $words[$i+1] : "");
98
+ $word_width = Font_Metrics::get_text_width($word, $font, $size, $word_spacing, $char_spacing);
99
+ if ( $width + $word_width + $mbp_width > $available_width )
100
+ break;
101
+
102
+ $width += $word_width;
103
+ $str .= $word;
104
+ }
105
+
106
+ $break_word = ($style->word_wrap === "break-word");
107
+
108
+ // The first word has overflowed. Force it onto the line
109
+ if ( $current_line_width == 0 && $width == 0 ) {
110
+
111
+ $s = "";
112
+ $last_width = 0;
113
+
114
+ if ( $break_word ) {
115
+ for ( $j = 0; $j < strlen($word); $j++ ) {
116
+ $s .= $word[$j];
117
+ $_width = Font_Metrics::get_text_width($s, $font, $size, $word_spacing, $char_spacing);
118
+ if ($_width > $available_width) {
119
+ break;
120
+ }
121
+
122
+ $last_width = $_width;
123
+ }
124
+ }
125
+
126
+ if ( $break_word && $last_width > 0 ) {
127
+ $width += $last_width;
128
+ $str .= substr($s, 0, -1);
129
+ }
130
+ else {
131
+ $width += $word_width;
132
+ $str .= $word;
133
+ }
134
+ }
135
+
136
+ $offset = mb_strlen($str);
137
+
138
+ // More debugging:
139
+ // pre_var_dump($str);
140
+ // pre_r("Width: ". $width);
141
+ // pre_r("Offset: " . $offset);
142
+
143
+ return $offset;
144
+
145
+ }
146
+
147
+ //........................................................................
148
+
149
+ protected function _newline_break($text) {
150
+
151
+ if ( ($i = mb_strpos($text, "\n")) === false)
152
+ return false;
153
+
154
+ return $i+1;
155
+
156
+ }
157
+
158
+ //........................................................................
159
+
160
+ protected function _layout_line() {
161
+ $frame = $this->_frame;
162
+ $style = $frame->get_style();
163
+ $text = $frame->get_text();
164
+ $size = $style->font_size;
165
+ $font = $style->font_family;
166
+
167
+ // Determine the text height
168
+ $style->height = Font_Metrics::get_font_height( $font, $size );
169
+
170
+ $split = false;
171
+ $add_line = false;
172
+
173
+ // Handle text transform:
174
+ // http://www.w3.org/TR/CSS21/text.html#propdef-text-transform
175
+ switch (strtolower($style->text_transform)) {
176
+ default: break;
177
+ case "capitalize": $text = mb_convert_case($text, MB_CASE_TITLE); break;
178
+ case "uppercase": $text = mb_convert_case($text, MB_CASE_UPPER); break;
179
+ case "lowercase": $text = mb_convert_case($text, MB_CASE_LOWER); break;
180
+ }
181
+
182
+ // Handle white-space property:
183
+ // http://www.w3.org/TR/CSS21/text.html#propdef-white-space
184
+ switch ($style->white_space) {
185
+
186
+ default:
187
+ case "normal":
188
+ $frame->set_text( $text = $this->_collapse_white_space($text) );
189
+ if ( $text == "" )
190
+ break;
191
+
192
+ $split = $this->_line_break($text);
193
+ break;
194
+
195
+ case "pre":
196
+ $split = $this->_newline_break($text);
197
+ $add_line = $split !== false;
198
+ break;
199
+
200
+ case "nowrap":
201
+ $frame->set_text( $text = $this->_collapse_white_space($text) );
202
+ break;
203
+
204
+ case "pre-wrap":
205
+ $split = $this->_newline_break($text);
206
+
207
+ if ( ($tmp = $this->_line_break($text)) !== false ) {
208
+ $add_line = $split < $tmp;
209
+ $split = min($tmp, $split);
210
+ } else
211
+ $add_line = true;
212
+
213
+ break;
214
+
215
+ case "pre-line":
216
+ // Collapse white-space except for \n
217
+ $frame->set_text( $text = preg_replace( "/[ \t]+/u", " ", $text ) );
218
+
219
+ if ( $text == "" )
220
+ break;
221
+
222
+ $split = $this->_newline_break($text);
223
+
224
+ if ( ($tmp = $this->_line_break($text)) !== false ) {
225
+ $add_line = $split < $tmp;
226
+ $split = min($tmp, $split);
227
+ } else
228
+ $add_line = true;
229
+
230
+ break;
231
+
232
+ }
233
+
234
+ // Handle degenerate case
235
+ if ( $text === "" )
236
+ return;
237
+
238
+ if ( $split !== false) {
239
+
240
+ // Handle edge cases
241
+ if ( $split == 0 && $text === " " ) {
242
+ $frame->set_text("");
243
+ return;
244
+ }
245
+
246
+ if ( $split == 0 ) {
247
+
248
+ // Trim newlines from the beginning of the line
249
+ //$this->_frame->set_text(ltrim($text, "\n\r"));
250
+
251
+ $this->_block_parent->add_line();
252
+ $frame->position();
253
+
254
+ // Layout the new line
255
+ $this->_layout_line();
256
+
257
+ }
258
+
259
+ else if ( $split < mb_strlen($frame->get_text()) ) {
260
+ // split the line if required
261
+ $frame->split_text($split);
262
+
263
+ $t = $frame->get_text();
264
+
265
+ // Remove any trailing newlines
266
+ if ( $split > 1 && $t[$split-1] === "\n" && !$frame->is_pre() )
267
+ $frame->set_text( mb_substr($t, 0, -1) );
268
+
269
+ // Do we need to trim spaces on wrapped lines? This might be desired, however, we
270
+ // can't trim the lines here or the layout will be affected if trimming the line
271
+ // leaves enough space to fit the next word in the text stream (because pdf layout
272
+ // is performed elsewhere).
273
+ /*if (!$this->_frame->get_prev_sibling() && !$this->_frame->get_next_sibling()) {
274
+ $t = $this->_frame->get_text();
275
+ $this->_frame->set_text( trim($t) );
276
+ }*/
277
+ }
278
+
279
+ if ( $add_line ) {
280
+ $this->_block_parent->add_line();
281
+ $frame->position();
282
+ }
283
+
284
+ } else {
285
+
286
+ // Remove empty space from start and end of line, but only where there isn't an inline sibling
287
+ // and the parent node isn't an inline element with siblings
288
+ // FIXME: Include non-breaking spaces?
289
+ $t = $frame->get_text();
290
+ $parent = $frame->get_parent();
291
+ $is_inline_frame = get_class($parent) === 'Inline_Frame_Decorator';
292
+
293
+ if ((!$is_inline_frame && !$frame->get_next_sibling()) ||
294
+ ( $is_inline_frame && !$parent->get_next_sibling())) {
295
+ $t = rtrim($t);
296
+ }
297
+
298
+ if ((!$is_inline_frame && !$frame->get_prev_sibling())/* ||
299
+ ( $is_inline_frame && !$parent->get_prev_sibling())*/) { // <span><span>A<span>B</span> C</span></span> fails (the whitespace is removed)
300
+ $t = ltrim($t);
301
+ }
302
+
303
+ $frame->set_text( $t );
304
+
305
+ }
306
+
307
+ // Set our new width
308
+ $width = $frame->recalculate_width();
309
+ }
310
+
311
+ //........................................................................
312
+
313
+ function reflow(Frame_Decorator $block = null) {
314
+ $frame = $this->_frame;
315
+ $page = $frame->get_root();
316
+ $page->check_forced_page_break($this->_frame);
317
+
318
+ if ( $page->is_full() )
319
+ return;
320
+
321
+ $this->_block_parent = /*isset($block) ? $block : */$frame->find_block_parent();
322
+
323
+ // Left trim the text if this is the first text on the line and we're
324
+ // collapsing white space
325
+ // if ( $this->_block_parent->get_current_line()->w == 0 &&
326
+ // ($frame->get_style()->white_space !== "pre" ||
327
+ // $frame->get_style()->white_space !== "pre-wrap") ) {
328
+ // $frame->set_text( ltrim( $frame->get_text() ) );
329
+ // }
330
+
331
+ $frame->position();
332
+
333
+ $this->_layout_line();
334
+
335
+ if ( $block ) {
336
+ $block->add_frame_to_line($frame);
337
+ }
338
+ }
339
+
340
+ //........................................................................
341
+
342
+ // Returns an array(0 => min, 1 => max, "min" => min, "max" => max) of the
343
+ // minimum and maximum widths of this frame
344
+ function get_min_max_width() {
345
+ /*if ( !is_null($this->_min_max_cache) )
346
+ return $this->_min_max_cache;*/
347
+ $frame = $this->_frame;
348
+ $style = $frame->get_style();
349
+ $this->_block_parent = $frame->find_block_parent();
350
+ $line_width = $frame->get_containing_block("w");
351
+
352
+ $str = $text = $frame->get_text();
353
+ $size = $style->font_size;
354
+ $font = $style->font_family;
355
+
356
+ $word_spacing = $style->length_in_pt($style->word_spacing);
357
+ $char_spacing = $style->length_in_pt($style->letter_spacing);
358
+
359
+ switch($style->white_space) {
360
+
361
+ default:
362
+ case "normal":
363
+ $str = preg_replace(self::$_whitespace_pattern," ", $str);
364
+ case "pre-wrap":
365
+ case "pre-line":
366
+
367
+ // Find the longest word (i.e. minimum length)
368
+
369
+ // This technique (using arrays & an anonymous function) is actually
370
+ // faster than doing a single-pass character by character scan. Heh,
371
+ // yes I took the time to bench it ;)
372
+ $words = array_flip(preg_split("/[\s-]+/u",$str, -1, PREG_SPLIT_DELIM_CAPTURE));
373
+ array_walk($words, create_function('&$val,$str',
374
+ '$val = Font_Metrics::get_text_width($str, "'.addslashes($font).'", '.$size.', '.$word_spacing.', '.$char_spacing.');'));
375
+ arsort($words);
376
+ $min = reset($words);
377
+ break;
378
+
379
+ case "pre":
380
+ $lines = array_flip(preg_split("/\n/u", $str));
381
+ array_walk($lines, create_function('&$val,$str',
382
+ '$val = Font_Metrics::get_text_width($str, "'.addslashes($font).'", '.$size.', '.$word_spacing.', '.$char_spacing.');'));
383
+
384
+ arsort($lines);
385
+ $min = reset($lines);
386
+ break;
387
+
388
+ case "nowrap":
389
+ $min = Font_Metrics::get_text_width($this->_collapse_white_space($str), $font, $size, $word_spacing, $char_spacing);
390
+ break;
391
+
392
+ }
393
+
394
+ switch ($style->white_space) {
395
+
396
+ default:
397
+ case "normal":
398
+ case "nowrap":
399
+ $str = preg_replace(self::$_whitespace_pattern," ", $text);
400
+ break;
401
+
402
+ case "pre-line":
403
+ //XXX: Is this correct?
404
+ $str = preg_replace( "/[ \t]+/u", " ", $text);
405
+
406
+ case "pre-wrap":
407
+ // Find the longest word (i.e. minimum length)
408
+ $lines = array_flip(preg_split("/\n/", $text));
409
+ array_walk($lines, create_function('&$val,$str',
410
+ '$val = Font_Metrics::get_text_width($str, "'.$font.'", '.$size.', '.$word_spacing.', '.$char_spacing.');'));
411
+ arsort($lines);
412
+ reset($lines);
413
+ $str = key($lines);
414
+ break;
415
+
416
+ }
417
+
418
+ $max = Font_Metrics::get_text_width($str, $font, $size, $word_spacing, $char_spacing);
419
+
420
+ $delta = $style->length_in_pt(array($style->margin_left,
421
+ $style->border_left_width,
422
+ $style->padding_left,
423
+ $style->padding_right,
424
+ $style->border_right_width,
425
+ $style->margin_right), $line_width);
426
+ $min += $delta;
427
+ $max += $delta;
428
+
429
+ return $this->_min_max_cache = array($min, $max, "min" => $min, "max" => $max);
430
+
431
+ }
432
+
433
+ }
dompdf/include/text_renderer.cls.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://www.dompdf.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Helmut Tischer <htischer@weihenstephan.org>
7
+ * @author Fabien M�nager <fabien.menager@gmail.com>
8
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
9
+ * @version $Id: text_renderer.cls.php 471 2012-02-06 21:59:10Z fabien.menager $
10
+ */
11
+
12
+ /**
13
+ * Renders text frames
14
+ *
15
+ * @access private
16
+ * @package dompdf
17
+ */
18
+ class Text_Renderer extends Abstract_Renderer {
19
+
20
+ const DECO_THICKNESS = 0.02; // Thickness of underline. Screen: 0.08, print: better less, e.g. 0.04
21
+
22
+ //Tweaking if $base and $descent are not accurate.
23
+ //Check method_exists( $this->_canvas, "get_cpdf" )
24
+ //- For cpdf these can and must stay 0, because font metrics are used directly.
25
+ //- For other renderers, if different values are wanted, separate the parameter sets.
26
+ // But $size and $size-$height seem to be accurate enough
27
+ const UNDERLINE_OFFSET = 0.0; // Relative to bottom of text, as fraction of height.
28
+ const OVERLINE_OFFSET = 0.0; // Relative to top of text
29
+ const LINETHROUGH_OFFSET = 0.0; // Relative to centre of text.
30
+ const DECO_EXTENSION = 0.0; // How far to extend lines past either end, in pt
31
+
32
+ //........................................................................
33
+
34
+ function render(Frame $frame) {
35
+ $text = $frame->get_text();
36
+ if ( trim($text) === "" )
37
+ return;
38
+
39
+ $style = $frame->get_style();
40
+ list($x, $y) = $frame->get_position();
41
+ $cb = $frame->get_containing_block();
42
+
43
+ if ( ($ml = $style->margin_left) === "auto" || $ml === "none" )
44
+ $ml = 0;
45
+
46
+ if ( ($pl = $style->padding_left) === "auto" || $pl === "none" )
47
+ $pl = 0;
48
+
49
+ if ( ($bl = $style->border_left_width) === "auto" || $bl === "none" )
50
+ $bl = 0;
51
+
52
+ $x += $style->length_in_pt( array($ml, $pl, $bl), $cb["w"] );
53
+
54
+ $font = $style->font_family;
55
+ $size = $frame_font_size = $style->font_size;
56
+ $height = $style->height;
57
+ $word_spacing = $frame->get_text_spacing() + $style->length_in_pt($style->word_spacing);
58
+ $char_spacing = $style->length_in_pt($style->letter_spacing);
59
+ $width = $style->width;
60
+
61
+ /*$text = str_replace(
62
+ array("{PAGE_NUM}"),
63
+ array($this->_canvas->get_page_number()),
64
+ $text
65
+ );*/
66
+
67
+ $this->_canvas->text($x, $y, $text,
68
+ $font, $size,
69
+ $style->color, $word_spacing, $char_spacing);
70
+
71
+ $line = $frame->get_containing_line();
72
+
73
+ // FIXME Instead of using the tallest frame to position,
74
+ // the decoration, the text should be well placed
75
+ if ( false && $line->tallest_frame ) {
76
+ $base_frame = $line->tallest_frame;
77
+ $style = $base_frame->get_style();
78
+ $size = $style->font_size;
79
+ $height = $line->h * ($size / $style->line_height);
80
+ }
81
+
82
+ if ( method_exists( $this->_canvas, "get_cpdf" ) ) {
83
+ $cpdf = $this->_canvas->get_cpdf();
84
+
85
+ //$cpdf_font = $cpdf->fonts[$style->font_family];
86
+ //$base = ($cpdf_font["UnderlinePosition"]*$size)/1000;
87
+ //$descent = (($cpdf_font["Ascender"]-$cpdf_font["Descender"])*$size)/1000;
88
+
89
+ $fontBBox = $cpdf->fonts[$style->font_family]['FontBBox'];
90
+ $base = (($fontBBox[3]*$size)/1000) * 0.90;
91
+ $descent = ($fontBBox[1]*$size)/1000;
92
+ //print '<pre>Text_Renderer cpdf:'.$base.' '.$descent.' '.$size.'</pre>';
93
+ } else {
94
+ //Descent is font part below baseline, typically negative. $height is about full height of font box.
95
+ //$descent = -$size/6; is less accurate, depends on font family.
96
+ // @todo Could we get font info for PDFlib adapter and others ?
97
+ $base = $size*1.08;
98
+ $descent = $size-$height;
99
+ //print '<pre>Text_Renderer other than cpdf:'.$base.' '.$descent.' '.$size.'</pre>';
100
+ }
101
+
102
+ // Handle text decoration:
103
+ // http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration
104
+
105
+ // Draw all applicable text-decorations. Start with the root and work our way down.
106
+ $p = $frame;
107
+ $stack = array();
108
+ while ( $p = $p->get_parent() )
109
+ $stack[] = $p;
110
+
111
+ while ( isset($stack[0]) ) {
112
+ $f = array_pop($stack);
113
+
114
+ if ( ($text_deco = $f->get_style()->text_decoration) === "none" )
115
+ continue;
116
+
117
+ $deco_y = $y; //$line->y;
118
+ $color = $f->get_style()->color;
119
+
120
+ switch ($text_deco) {
121
+
122
+ default:
123
+ continue;
124
+
125
+ case "underline":
126
+ $deco_y += $base - $descent + $size * (self::UNDERLINE_OFFSET - self::DECO_THICKNESS/2);
127
+ break;
128
+
129
+ case "overline":
130
+ $deco_y += $size * (self::OVERLINE_OFFSET + self::DECO_THICKNESS/2);
131
+ break;
132
+
133
+ case "line-through":
134
+ $deco_y += $base * 0.7 + $size * self::LINETHROUGH_OFFSET;
135
+ break;
136
+ }
137
+
138
+ $dx = 0;
139
+ $x1 = $x - self::DECO_EXTENSION;
140
+ $x2 = $x + $width + $dx + self::DECO_EXTENSION;
141
+ $this->_canvas->line($x1, $deco_y, $x2, $deco_y, $color, $size * self::DECO_THICKNESS);
142
+
143
+ }
144
+
145
+ if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES) {
146
+ $text_width = Font_Metrics::get_text_width($text, $font, $frame_font_size);
147
+ $this->_debug_layout(array($x, $y, $text_width+($line->wc-1)*$word_spacing, $frame_font_size), "orange", array(0.5, 0.5));
148
+ }
149
+ }
150
+ }
dompdf/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php header("Location: www/"); ?>
dompdf/lib/_notes/dwsync.xml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <dwsync>
3
+ <file name="class.pdf.php" server="ftp.danielmarks.com.au" local="129908529600000000" remote="129908529600000000" />
4
+ <file name="class.pdf.php" server="216.235.107.57" local="129908529600000000" remote="129913291200000000" />
5
+ </dwsync>
dompdf/lib/class.pdf.php ADDED
@@ -0,0 +1,4969 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A PHP class to provide the basic functionality to create a pdf document without
4
+ * any requirement for additional modules.
5
+ *
6
+ * Extended by Orion Richardson to support Unicode / UTF-8 characters using
7
+ * TCPDF and others as a guide.
8
+ *
9
+ * @author Wayne Munro <pdf@ros.co.nz>
10
+ * @author Orion Richardson <orionr@yahoo.com>
11
+ * @author Helmut Tischer <htischer@weihenstephan.org>
12
+ * @author Ryan H. Masten <ryan.masten@gmail.com>
13
+ * @author Brian Sweeney <eclecticgeek@gmail.com>
14
+ * @author Fabien M�nager <fabien.menager@gmail.com>
15
+ * @version $Id: class.pdf.php 469 2012-02-05 22:25:30Z fabien.menager $
16
+ * @license Public Domain http://creativecommons.org/licenses/publicdomain/
17
+ * @package Cpdf
18
+ */
19
+ class Cpdf {
20
+
21
+ /**
22
+ * @var integer The current number of pdf objects in the document
23
+ */
24
+ public $numObj = 0;
25
+
26
+ /**
27
+ * @var array This array contains all of the pdf objects, ready for final assembly
28
+ */
29
+ public $objects = array();
30
+
31
+ /**
32
+ * @var integer The objectId (number within the objects array) of the document catalog
33
+ */
34
+ public $catalogId;
35
+
36
+ /**
37
+ * @var array Array carrying information about the fonts that the system currently knows about
38
+ * Used to ensure that a font is not loaded twice, among other things
39
+ */
40
+ public $fonts = array();
41
+
42
+ /**
43
+ * @var string The default font metrics file to use if no other font has been loaded.
44
+ * The path to the directory containing the font metrics should be included
45
+ */
46
+ public $defaultFont = './fonts/Helvetica.afm';
47
+
48
+ /**
49
+ * @string A record of the current font
50
+ */
51
+ public $currentFont = '';
52
+
53
+ /**
54
+ * @var string The current base font
55
+ */
56
+ public $currentBaseFont = '';
57
+
58
+ /**
59
+ * @var integer The number of the current font within the font array
60
+ */
61
+ public $currentFontNum = 0;
62
+
63
+ /**
64
+ * @var integer
65
+ */
66
+ public $currentNode;
67
+
68
+ /**
69
+ * @var integer Object number of the current page
70
+ */
71
+ public $currentPage;
72
+
73
+ /**
74
+ * @var integer Object number of the currently active contents block
75
+ */
76
+ public $currentContents;
77
+
78
+ /**
79
+ * @var integer Number of fonts within the system
80
+ */
81
+ public $numFonts = 0;
82
+
83
+ /**
84
+ * @var integer Number of graphic state resources used
85
+ */
86
+ private $numStates = 0;
87
+
88
+ /**
89
+ * @var array Current colour for fill operations, defaults to inactive value,
90
+ * all three components should be between 0 and 1 inclusive when active
91
+ */
92
+ public $currentColour = null;
93
+
94
+ /**
95
+ * @var array Current colour for stroke operations (lines etc.)
96
+ */
97
+ public $currentStrokeColour = null;
98
+
99
+ /**
100
+ * @var string Current style that lines are drawn in
101
+ */
102
+ public $currentLineStyle = '';
103
+
104
+ /**
105
+ * @var array Current line transparency (partial graphics state)
106
+ */
107
+ public $currentLineTransparency = array("mode" => "Normal", "opacity" => 1.0);
108
+
109
+ /**
110
+ * array Current fill transparency (partial graphics state)
111
+ */
112
+ public $currentFillTransparency = array("mode" => "Normal", "opacity" => 1.0);
113
+
114
+ /**
115
+ * @var array An array which is used to save the state of the document, mainly the colours and styles
116
+ * it is used to temporarily change to another state, the change back to what it was before
117
+ */
118
+ public $stateStack = array();
119
+
120
+ /**
121
+ * @var integer Number of elements within the state stack
122
+ */
123
+ public $nStateStack = 0;
124
+
125
+ /**
126
+ * @var integer Number of page objects within the document
127
+ */
128
+ public $numPages = 0;
129
+
130
+ /**
131
+ * @var array Object Id storage stack
132
+ */
133
+ public $stack = array();
134
+
135
+ /**
136
+ * @var integer Number of elements within the object Id storage stack
137
+ */
138
+ public $nStack = 0;
139
+
140
+ /**
141
+ * an array which contains information about the objects which are not firmly attached to pages
142
+ * these have been added with the addObject function
143
+ */
144
+ public $looseObjects = array();
145
+
146
+ /**
147
+ * array contains infomation about how the loose objects are to be added to the document
148
+ */
149
+ public $addLooseObjects = array();
150
+
151
+ /**
152
+ * @var integer The objectId of the information object for the document
153
+ * this contains authorship, title etc.
154
+ */
155
+ public $infoObject = 0;
156
+
157
+ /**
158
+ * @var integer Number of images being tracked within the document
159
+ */
160
+ public $numImages = 0;
161
+
162
+ /**
163
+ * @var array An array containing options about the document
164
+ * it defaults to turning on the compression of the objects
165
+ */
166
+ public $options = array('compression'=>true);
167
+
168
+ /**
169
+ * @var integer The objectId of the first page of the document
170
+ */
171
+ public $firstPageId;
172
+
173
+ /**
174
+ * @var float Used to track the last used value of the inter-word spacing, this is so that it is known
175
+ * when the spacing is changed.
176
+ */
177
+ public $wordSpaceAdjust = 0;
178
+
179
+ /**
180
+ * @var float Used to track the last used value of the inter-letter spacing, this is so that it is known
181
+ * when the spacing is changed.
182
+ */
183
+ public $charSpaceAdjust = 0;
184
+
185
+ /**
186
+ * @var integer The object Id of the procset object
187
+ */
188
+ public $procsetObjectId;
189
+
190
+ /**
191
+ * @var array Store the information about the relationship between font families
192
+ * this used so that the code knows which font is the bold version of another font, etc.
193
+ * the value of this array is initialised in the constuctor function.
194
+ */
195
+ public $fontFamilies = array();
196
+
197
+ /**
198
+ * @var string Folder for php serialized formats of font metrics files.
199
+ * If empty string, use same folder as original metrics files.
200
+ * This can be passed in from class creator.
201
+ * If this folder does not exist or is not writable, Cpdf will be **much** slower.
202
+ * Because of potential trouble with php safe mode, folder cannot be created at runtime.
203
+ */
204
+ public $fontcache = '';
205
+
206
+ /**
207
+ * @var integer The version of the font metrics cache file.
208
+ * This value must be manually incremented whenever the internal font data structure is modified.
209
+ */
210
+ public $fontcacheVersion = 5;
211
+
212
+ /**
213
+ * @var string Temporary folder.
214
+ * If empty string, will attempty system tmp folder.
215
+ * This can be passed in from class creator.
216
+ * Only used for conversion of gd images to jpeg images.
217
+ */
218
+ public $tmp = '';
219
+
220
+ /**
221
+ * @var string Track if the current font is bolded or italicised
222
+ */
223
+ public $currentTextState = '';
224
+
225
+ /**
226
+ * @var string Messages are stored here during processing, these can be selected afterwards to give some useful debug information
227
+ */
228
+ public $messages = '';
229
+
230
+ /**
231
+ * @var string The ancryption array for the document encryption is stored here
232
+ */
233
+ public $arc4 = '';
234
+
235
+ /**
236
+ * @var integer The object Id of the encryption information
237
+ */
238
+ public $arc4_objnum = 0;
239
+
240
+ /**
241
+ * @var string The file identifier, used to uniquely identify a pdf document
242
+ */
243
+ public $fileIdentifier = '';
244
+
245
+ /**
246
+ * @var boolean A flag to say if a document is to be encrypted or not
247
+ */
248
+ public $encrypted = false;
249
+
250
+ /**
251
+ * @var string The encryption key for the encryption of all the document content (structure is not encrypted)
252
+ */
253
+ public $encryptionKey = '';
254
+
255
+ /**
256
+ * @var array Array which forms a stack to keep track of nested callback functions
257
+ */
258
+ public $callback = array();
259
+
260
+ /**
261
+ * @var integer The number of callback functions in the callback array
262
+ */
263
+ public $nCallback = 0;
264
+
265
+ /**
266
+ * @var array Store label->id pairs for named destinations, these will be used to replace internal links
267
+ * done this way so that destinations can be defined after the location that links to them
268
+ */
269
+ public $destinations = array();
270
+
271
+ /**
272
+ * @var array Store the stack for the transaction commands, each item in here is a record of the values of all the
273
+ * publiciables within the class, so that the user can rollback at will (from each 'start' command)
274
+ * note that this includes the objects array, so these can be large.
275
+ */
276
+ public $checkpoint = '';
277
+
278
+ /**
279
+ * @var array Table of Image origin filenames and image labels which were already added with o_image().
280
+ * Allows to merge identical images
281
+ */
282
+ public $imagelist = array();
283
+
284
+ /**
285
+ * @var boolean Whether the text passed in should be treated as Unicode or just local character set.
286
+ */
287
+ public $isUnicode = false;
288
+
289
+ /**
290
+ * @var string the JavaScript code of the document
291
+ */
292
+ public $javascript = '';
293
+
294
+ /**
295
+ * @var boolean whether the compression is possible
296
+ */
297
+ protected $compressionReady = false;
298
+
299
+ /**
300
+ * @var array Current page size
301
+ */
302
+ protected $currentPageSize = array("width" => 0, "height" => 0);
303
+
304
+ /**
305
+ * @var array All the chars that will be required in the font subsets
306
+ */
307
+ protected $stringSubsets = array();
308
+
309
+ /**
310
+ * @var string The target internal encoding
311
+ */
312
+ static protected $targetEncoding = 'iso-8859-1';
313
+
314
+ /**
315
+ * @var array The list of the core fonts
316
+ */
317
+ static protected $coreFonts = array(
318
+ 'courier', 'courier-bold', 'courier-oblique', 'courier-boldoblique',
319
+ 'helvetica', 'helvetica-bold', 'helvetica-oblique', 'helvetica-boldoblique',
320
+ 'times-roman', 'times-bold', 'times-italic', 'times-bolditalic',
321
+ 'symbol', 'zapfdingbats'
322
+ );
323
+
324
+ /**
325
+ * class constructor
326
+ * this will start a new document
327
+ * @var array $pageSize Array of 4 numbers, defining the bottom left and upper right corner of the page. first two are normally zero.
328
+ * @var boolean $isUnicode Whether text will be treated as Unicode or not.
329
+ * @var string $fontcache The font cache folder
330
+ * @var string $tmp The temporary folder
331
+ */
332
+ function __construct ($pageSize = array(0, 0, 612, 792), $isUnicode = false, $fontcache = '', $tmp = '') {
333
+ $this->isUnicode = $isUnicode;
334
+ $this->fontcache = $fontcache;
335
+ $this->tmp = $tmp;
336
+ $this->newDocument($pageSize);
337
+
338
+ $this->compressionReady = function_exists('gzcompress');
339
+
340
+ if ( in_array('Windows-1252', mb_list_encodings()) ) {
341
+ self::$targetEncoding = 'Windows-1252';
342
+ }
343
+
344
+ // also initialize the font families that are known about already
345
+ $this->setFontFamily('init');
346
+ // $this->fileIdentifier = md5('xxxxxxxx'.time());
347
+ }
348
+
349
+ /**
350
+ * Document object methods (internal use only)
351
+ *
352
+ * There is about one object method for each type of object in the pdf document
353
+ * Each function has the same call list ($id,$action,$options).
354
+ * $id = the object ID of the object, or what it is to be if it is being created
355
+ * $action = a string specifying the action to be performed, though ALL must support:
356
+ * 'new' - create the object with the id $id
357
+ * 'out' - produce the output for the pdf object
358
+ * $options = optional, a string or array containing the various parameters for the object
359
+ *
360
+ * These, in conjunction with the output function are the ONLY way for output to be produced
361
+ * within the pdf 'file'.
362
+ */
363
+
364
+ /**
365
+ *destination object, used to specify the location for the user to jump to, presently on opening
366
+ */
367
+ protected function o_destination($id, $action, $options = '') {
368
+ if ($action !== 'new') {
369
+ $o = & $this->objects[$id];
370
+ }
371
+
372
+ switch ($action) {
373
+ case 'new':
374
+ $this->objects[$id] = array('t'=>'destination', 'info'=>array());
375
+ $tmp = '';
376
+ switch ($options['type']) {
377
+ case 'XYZ':
378
+ case 'FitR':
379
+ $tmp = ' '.$options['p3'].$tmp;
380
+ case 'FitH':
381
+ case 'FitV':
382
+ case 'FitBH':
383
+ case 'FitBV':
384
+ $tmp = ' '.$options['p1'].' '.$options['p2'].$tmp;
385
+ case 'Fit':
386
+ case 'FitB':
387
+ $tmp = $options['type'].$tmp;
388
+ $this->objects[$id]['info']['string'] = $tmp;
389
+ $this->objects[$id]['info']['page'] = $options['page'];
390
+ }
391
+ break;
392
+
393
+ case 'out':
394
+ $tmp = $o['info'];
395
+ $res = "\n$id 0 obj\n".'['.$tmp['page'].' 0 R /'.$tmp['string']."]\nendobj";
396
+ return $res;
397
+ }
398
+ }
399
+
400
+ /**
401
+ * set the viewer preferences
402
+ */
403
+ protected function o_viewerPreferences($id, $action, $options = '') {
404
+ if ($action !== 'new') {
405
+ $o = & $this->objects[$id];
406
+ }
407
+
408
+ switch ($action) {
409
+ case 'new':
410
+ $this->objects[$id] = array('t'=>'viewerPreferences', 'info'=>array());
411
+ break;
412
+
413
+ case 'add':
414
+ foreach($options as $k=>$v) {
415
+ switch ($k) {
416
+ case 'HideToolbar':
417
+ case 'HideMenubar':
418
+ case 'HideWindowUI':
419
+ case 'FitWindow':
420
+ case 'CenterWindow':
421
+ case 'NonFullScreenPageMode':
422
+ case 'Direction':
423
+ $o['info'][$k] = $v;
424
+ break;
425
+ }
426
+ }
427
+ break;
428
+
429
+ case 'out':
430
+ $res = "\n$id 0 obj\n<< ";
431
+ foreach($o['info'] as $k=>$v) {
432
+ $res.= "\n/$k $v";
433
+ }
434
+ $res.= "\n>>\n";
435
+ return $res;
436
+ }
437
+ }
438
+
439
+ /**
440
+ * define the document catalog, the overall controller for the document
441
+ */
442
+ protected function o_catalog($id, $action, $options = '') {
443
+ if ($action !== 'new') {
444
+ $o = & $this->objects[$id];
445
+ }
446
+
447
+ switch ($action) {
448
+ case 'new':
449
+ $this->objects[$id] = array('t'=>'catalog', 'info'=>array());
450
+ $this->catalogId = $id;
451
+ break;
452
+
453
+ case 'outlines':
454
+ case 'pages':
455
+ case 'openHere':
456
+ case 'javascript':
457
+ $o['info'][$action] = $options;
458
+ break;
459
+
460
+ case 'viewerPreferences':
461
+ if (!isset($o['info']['viewerPreferences'])) {
462
+ $this->numObj++;
463
+ $this->o_viewerPreferences($this->numObj, 'new');
464
+ $o['info']['viewerPreferences'] = $this->numObj;
465
+ }
466
+
467
+ $vp = $o['info']['viewerPreferences'];
468
+ $this->o_viewerPreferences($vp, 'add', $options);
469
+
470
+ break;
471
+
472
+ case 'out':
473
+ $res = "\n$id 0 obj\n<< /Type /Catalog";
474
+
475
+ foreach($o['info'] as $k=>$v) {
476
+ switch ($k) {
477
+ case 'outlines':
478
+ $res.= "\n/Outlines $v 0 R";
479
+ break;
480
+
481
+ case 'pages':
482
+ $res.= "\n/Pages $v 0 R";
483
+ break;
484
+
485
+ case 'viewerPreferences':
486
+ $res.= "\n/ViewerPreferences $v 0 R";
487
+ break;
488
+
489
+ case 'openHere':
490
+ $res.= "\n/OpenAction $v 0 R";
491
+ break;
492
+
493
+ case 'javascript':
494
+ $res.= "\n/Names <</JavaScript $v 0 R>>";
495
+ break;
496
+ }
497
+ }
498
+
499
+ $res.= " >>\nendobj";
500
+ return $res;
501
+ }
502
+ }
503
+
504
+ /**
505
+ * object which is a parent to the pages in the document
506
+ */
507
+ protected function o_pages($id, $action, $options = '') {
508
+ if ($action !== 'new') {
509
+ $o = & $this->objects[$id];
510
+ }
511
+
512
+ switch ($action) {
513
+ case 'new':
514
+ $this->objects[$id] = array('t'=>'pages', 'info'=>array());
515
+ $this->o_catalog($this->catalogId, 'pages', $id);
516
+ break;
517
+
518
+ case 'page':
519
+ if (!is_array($options)) {
520
+ // then it will just be the id of the new page
521
+ $o['info']['pages'][] = $options;
522
+ } else {
523
+ // then it should be an array having 'id','rid','pos', where rid=the page to which this one will be placed relative
524
+ // and pos is either 'before' or 'after', saying where this page will fit.
525
+ if (isset($options['id']) && isset($options['rid']) && isset($options['pos'])) {
526
+ $i = array_search($options['rid'], $o['info']['pages']);
527
+ if (isset($o['info']['pages'][$i]) && $o['info']['pages'][$i] == $options['rid']) {
528
+
529
+ // then there is a match
530
+ // make a space
531
+ switch ($options['pos']) {
532
+ case 'before':
533
+ $k = $i;
534
+ break;
535
+
536
+ case 'after':
537
+ $k = $i+1;
538
+ break;
539
+
540
+ default:
541
+ $k = -1;
542
+ break;
543
+ }
544
+
545
+ if ($k >= 0) {
546
+ for ($j = count($o['info']['pages']) -1;$j >= $k;$j--) {
547
+ $o['info']['pages'][$j+1] = $o['info']['pages'][$j];
548
+ }
549
+
550
+ $o['info']['pages'][$k] = $options['id'];
551
+ }
552
+ }
553
+ }
554
+ }
555
+ break;
556
+
557
+ case 'procset':
558
+ $o['info']['procset'] = $options;
559
+ break;
560
+
561
+ case 'mediaBox':
562
+ $o['info']['mediaBox'] = $options;
563
+ // which should be an array of 4 numbers
564
+ $this->currentPageSize = array('width' => $options[2], 'height' => $options[3]);
565
+ break;
566
+
567
+ case 'font':
568
+ $o['info']['fonts'][] = array('objNum'=>$options['objNum'], 'fontNum'=>$options['fontNum']);
569
+ break;
570
+
571
+ case 'extGState':
572
+ $o['info']['extGStates'][] = array('objNum' => $options['objNum'], 'stateNum' => $options['stateNum']);
573
+ break;
574
+
575
+ case 'xObject':
576
+ $o['info']['xObjects'][] = array('objNum'=>$options['objNum'], 'label'=>$options['label']);
577
+ break;
578
+
579
+ case 'out':
580
+ if (count($o['info']['pages'])) {
581
+ $res = "\n$id 0 obj\n<< /Type /Pages\n/Kids [";
582
+ foreach($o['info']['pages'] as $v) {
583
+ $res.= "$v 0 R\n";
584
+ }
585
+
586
+ $res.= "]\n/Count ".count($this->objects[$id]['info']['pages']);
587
+
588
+ if ( (isset($o['info']['fonts']) && count($o['info']['fonts'])) ||
589
+ isset($o['info']['procset']) ||
590
+ (isset($o['info']['extGStates']) && count($o['info']['extGStates']))) {
591
+ $res.= "\n/Resources <<";
592
+
593
+ if (isset($o['info']['procset'])) {
594
+ $res.= "\n/ProcSet ".$o['info']['procset']." 0 R";
595
+ }
596
+
597
+ if (isset($o['info']['fonts']) && count($o['info']['fonts'])) {
598
+ $res.= "\n/Font << ";
599
+ foreach($o['info']['fonts'] as $finfo) {
600
+ $res.= "\n/F".$finfo['fontNum']." ".$finfo['objNum']." 0 R";
601
+ }
602
+ $res.= "\n>>";
603
+ }
604
+
605
+ if (isset($o['info']['xObjects']) && count($o['info']['xObjects'])) {
606
+ $res.= "\n/XObject << ";
607
+ foreach($o['info']['xObjects'] as $finfo) {
608
+ $res.= "\n/".$finfo['label']." ".$finfo['objNum']." 0 R";
609
+ }
610
+ $res.= "\n>>";
611
+ }
612
+
613
+ if ( isset($o['info']['extGStates']) && count($o['info']['extGStates'])) {
614
+ $res.= "\n/ExtGState << ";
615
+ foreach ($o['info']['extGStates'] as $gstate) {
616
+ $res.= "\n/GS" . $gstate['stateNum'] . " " . $gstate['objNum'] . " 0 R";
617
+ }
618
+ $res.= "\n>>";
619
+ }
620
+
621
+ $res.= "\n>>";
622
+ if (isset($o['info']['mediaBox'])) {
623
+ $tmp = $o['info']['mediaBox'];
624
+ $res.= "\n/MediaBox [".sprintf('%.3F %.3F %.3F %.3F', $tmp[0], $tmp[1], $tmp[2], $tmp[3]) .']';
625
+ }
626
+ }
627
+
628
+ $res.= "\n >>\nendobj";
629
+ } else {
630
+ $res = "\n$id 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj";
631
+ }
632
+
633
+ return $res;
634
+ }
635
+ }
636
+
637
+ /**
638
+ * define the outlines in the doc, empty for now
639
+ */
640
+ protected function o_outlines($id, $action, $options = '') {
641
+ if ($action !== 'new') {
642
+ $o = & $this->objects[$id];
643
+ }
644
+
645
+ switch ($action) {
646
+ case 'new':
647
+ $this->objects[$id] = array('t'=>'outlines', 'info'=>array('outlines'=>array()));
648
+ $this->o_catalog($this->catalogId, 'outlines', $id);
649
+ break;
650
+
651
+ case 'outline':
652
+ $o['info']['outlines'][] = $options;
653
+ break;
654
+
655
+ case 'out':
656
+ if (count($o['info']['outlines'])) {
657
+ $res = "\n$id 0 obj\n<< /Type /Outlines /Kids [";
658
+ foreach($o['info']['outlines'] as $v) {
659
+ $res.= "$v 0 R ";
660
+ }
661
+
662
+ $res.= "] /Count ".count($o['info']['outlines']) ." >>\nendobj";
663
+ } else {
664
+ $res = "\n$id 0 obj\n<< /Type /Outlines /Count 0 >>\nendobj";
665
+ }
666
+
667
+ return $res;
668
+ }
669
+ }
670
+
671
+ /**
672
+ * an object to hold the font description
673
+ */
674
+ protected function o_font($id, $action, $options = '') {
675
+ if ($action !== 'new') {
676
+ $o = & $this->objects[$id];
677
+ }
678
+
679
+ switch ($action) {
680
+ case 'new':
681
+ $this->objects[$id] = array('t' => 'font', 'info' => array('name' => $options['name'], 'fontFileName' => $options['fontFileName'], 'SubType' => 'Type1'));
682
+ $fontNum = $this->numFonts;
683
+ $this->objects[$id]['info']['fontNum'] = $fontNum;
684
+
685
+ // deal with the encoding and the differences
686
+ if (isset($options['differences'])) {
687
+ // then we'll need an encoding dictionary
688
+ $this->numObj++;
689
+ $this->o_fontEncoding($this->numObj, 'new', $options);
690
+ $this->objects[$id]['info']['encodingDictionary'] = $this->numObj;
691
+ } else if (isset($options['encoding'])) {
692
+ // we can specify encoding here
693
+ switch ($options['encoding']) {
694
+ case 'WinAnsiEncoding':
695
+ case 'MacRomanEncoding':
696
+ case 'MacExpertEncoding':
697
+ $this->objects[$id]['info']['encoding'] = $options['encoding'];
698
+ break;
699
+
700
+ case 'none':
701
+ break;
702
+
703
+ default:
704
+ $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
705
+ break;
706
+ }
707
+ } else {
708
+ $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
709
+ }
710
+
711
+ if ($this->fonts[$options['fontFileName']]['isUnicode']) {
712
+ // For Unicode fonts, we need to incorporate font data into
713
+ // sub-sections that are linked from the primary font section.
714
+ // Look at o_fontGIDtoCID and o_fontDescendentCID functions
715
+ // for more informaiton.
716
+ //
717
+ // All of this code is adapted from the excellent changes made to
718
+ // transform FPDF to TCPDF (http://tcpdf.sourceforge.net/)
719
+
720
+ $toUnicodeId = ++$this->numObj;
721
+ $this->o_contents($toUnicodeId, 'new', 'raw');
722
+ $this->objects[$id]['info']['toUnicode'] = $toUnicodeId;
723
+
724
+ $stream = <<<EOT
725
+ /CIDInit /ProcSet findresource begin
726
+ 12 dict begin
727
+ begincmap
728
+ /CIDSystemInfo
729
+ <</Registry (Adobe)
730
+ /Ordering (UCS)
731
+ /Supplement 0
732
+ >> def
733
+ /CMapName /Adobe-Identity-UCS def
734
+ /CMapType 2 def
735
+ 1 begincodespacerange
736
+ <0000> <FFFF>
737
+ endcodespacerange
738
+ 1 beginbfrange
739
+ <0000> <FFFF> <0000>
740
+ endbfrange
741
+ endcmap
742
+ CMapName currentdict /CMap defineresource pop
743
+ end
744
+ end
745
+ EOT;
746
+
747
+ $res = "<</Length " . mb_strlen($stream, '8bit') . " >>\n";
748
+ $res .= "stream\n" . $stream . "endstream";
749
+
750
+ $this->objects[$toUnicodeId]['c'] = $res;
751
+
752
+ $cidFontId = ++$this->numObj;
753
+ $this->o_fontDescendentCID($cidFontId, 'new', $options);
754
+ $this->objects[$id]['info']['cidFont'] = $cidFontId;
755
+ }
756
+
757
+ // also tell the pages node about the new font
758
+ $this->o_pages($this->currentNode, 'font', array('fontNum' => $fontNum, 'objNum' => $id));
759
+ break;
760
+
761
+ case 'add':
762
+ foreach ($options as $k => $v) {
763
+ switch ($k) {
764
+ case 'BaseFont':
765
+ $o['info']['name'] = $v;
766
+ break;
767
+ case 'FirstChar':
768
+ case 'LastChar':
769
+ case 'Widths':
770
+ case 'FontDescriptor':
771
+ case 'SubType':
772
+ $this->addMessage('o_font '.$k." : ".$v);
773
+ $o['info'][$k] = $v;
774
+ break;
775
+ }
776
+ }
777
+
778
+ // pass values down to descendent font
779
+ if (isset($o['info']['cidFont'])) {
780
+ $this->o_fontDescendentCID($o['info']['cidFont'], 'add', $options);
781
+ }
782
+ break;
783
+
784
+ case 'out':
785
+ if ($this->fonts[$this->objects[$id]['info']['fontFileName']]['isUnicode']) {
786
+ // For Unicode fonts, we need to incorporate font data into
787
+ // sub-sections that are linked from the primary font section.
788
+ // Look at o_fontGIDtoCID and o_fontDescendentCID functions
789
+ // for more informaiton.
790
+ //
791
+ // All of this code is adapted from the excellent changes made to
792
+ // transform FPDF to TCPDF (http://tcpdf.sourceforge.net/)
793
+
794
+ $res = "\n$id 0 obj\n<</Type /Font\n/Subtype /Type0\n";
795
+ $res.= "/BaseFont /".$o['info']['name']."\n";
796
+
797
+ // The horizontal identity mapping for 2-byte CIDs; may be used
798
+ // with CIDFonts using any Registry, Ordering, and Supplement values.
799
+ $res.= "/Encoding /Identity-H\n";
800
+ $res.= "/DescendantFonts [".$o['info']['cidFont']." 0 R]\n";
801
+ $res.= "/ToUnicode ".$o['info']['toUnicode']." 0 R\n";
802
+ $res.= ">>\n";
803
+ $res.= "endobj";
804
+ } else {
805
+ $res = "\n$id 0 obj\n<< /Type /Font\n/Subtype /".$o['info']['SubType']."\n";
806
+ $res.= "/Name /F".$o['info']['fontNum']."\n";
807
+ $res.= "/BaseFont /".$o['info']['name']."\n";
808
+
809
+ if (isset($o['info']['encodingDictionary'])) {
810
+ // then place a reference to the dictionary
811
+ $res.= "/Encoding ".$o['info']['encodingDictionary']." 0 R\n";
812
+ } else if (isset($o['info']['encoding'])) {
813
+ // use the specified encoding
814
+ $res.= "/Encoding /".$o['info']['encoding']."\n";
815
+ }
816
+
817
+ if (isset($o['info']['FirstChar'])) {
818
+ $res.= "/FirstChar ".$o['info']['FirstChar']."\n";
819
+ }
820
+
821
+ if (isset($o['info']['LastChar'])) {
822
+ $res.= "/LastChar ".$o['info']['LastChar']."\n";
823
+ }
824
+
825
+ if (isset($o['info']['Widths'])) {
826
+ $res.= "/Widths ".$o['info']['Widths']." 0 R\n";
827
+ }
828
+
829
+ if (isset($o['info']['FontDescriptor'])) {
830
+ $res.= "/FontDescriptor ".$o['info']['FontDescriptor']." 0 R\n";
831
+ }
832
+
833
+ $res.= ">>\n";
834
+ $res.= "endobj";
835
+ }
836
+
837
+ return $res;
838
+ }
839
+ }
840
+
841
+ /**
842
+ * a font descriptor, needed for including additional fonts
843
+ */
844
+ protected function o_fontDescriptor($id, $action, $options = '') {
845
+ if ($action !== 'new') {
846
+ $o = & $this->objects[$id];
847
+ }
848
+
849
+ switch ($action) {
850
+ case 'new':
851
+ $this->objects[$id] = array('t'=>'fontDescriptor', 'info'=>$options);
852
+ break;
853
+
854
+ case 'out':
855
+ $res = "\n$id 0 obj\n<< /Type /FontDescriptor\n";
856
+ foreach ($o['info'] as $label => $value) {
857
+ switch ($label) {
858
+ case 'Ascent':
859
+ case 'CapHeight':
860
+ case 'Descent':
861
+ case 'Flags':
862
+ case 'ItalicAngle':
863
+ case 'StemV':
864
+ case 'AvgWidth':
865
+ case 'Leading':
866
+ case 'MaxWidth':
867
+ case 'MissingWidth':
868
+ case 'StemH':
869
+ case 'XHeight':
870
+ case 'CharSet':
871
+ if (mb_strlen($value, '8bit')) {
872
+ $res.= "/$label $value\n";
873
+ }
874
+
875
+ break;
876
+ case 'FontFile':
877
+ case 'FontFile2':
878
+ case 'FontFile3':
879
+ $res.= "/$label $value 0 R\n";
880
+ break;
881
+
882
+ case 'FontBBox':
883
+ $res.= "/$label [$value[0] $value[1] $value[2] $value[3]]\n";
884
+ break;
885
+
886
+ case 'FontName':
887
+ $res.= "/$label /$value\n";
888
+ break;
889
+ }
890
+ }
891
+
892
+ $res.= ">>\nendobj";
893
+
894
+ return $res;
895
+ }
896
+ }
897
+
898
+ /**
899
+ * the font encoding
900
+ */
901
+ protected function o_fontEncoding($id, $action, $options = '') {
902
+ if ($action !== 'new') {
903
+ $o = & $this->objects[$id];
904
+ }
905
+
906
+ switch ($action) {
907
+ case 'new':
908
+ // the options array should contain 'differences' and maybe 'encoding'
909
+ $this->objects[$id] = array('t'=>'fontEncoding', 'info'=>$options);
910
+ break;
911
+
912
+ case 'out':
913
+ $res = "\n$id 0 obj\n<< /Type /Encoding\n";
914
+ if (!isset($o['info']['encoding'])) {
915
+ $o['info']['encoding'] = 'WinAnsiEncoding';
916
+ }
917
+
918
+ if ($o['info']['encoding'] !== 'none') {
919
+ $res.= "/BaseEncoding /".$o['info']['encoding']."\n";
920
+ }
921
+
922
+ $res.= "/Differences \n[";
923
+
924
+ $onum = -100;
925
+
926
+ foreach($o['info']['differences'] as $num=>$label) {
927
+ if ($num != $onum+1) {
928
+ // we cannot make use of consecutive numbering
929
+ $res.= "\n$num /$label";
930
+ } else {
931
+ $res.= " /$label";
932
+ }
933
+
934
+ $onum = $num;
935
+ }
936
+
937
+ $res.= "\n]\n>>\nendobj";
938
+ return $res;
939
+ }
940
+ }
941
+
942
+ /**
943
+ * a descendent cid font, needed for unicode fonts
944
+ */
945
+ protected function o_fontDescendentCID($id, $action, $options = '') {
946
+ if ($action !== 'new') {
947
+ $o = & $this->objects[$id];
948
+ }
949
+
950
+ switch ($action) {
951
+ case 'new':
952
+ $this->objects[$id] = array('t'=>'fontDescendentCID', 'info'=>$options);
953
+
954
+ // we need a CID system info section
955
+ $cidSystemInfoId = ++$this->numObj;
956
+ $this->o_contents($cidSystemInfoId, 'new', 'raw');
957
+ $this->objects[$id]['info']['cidSystemInfo'] = $cidSystemInfoId;
958
+ $res= "<</Registry (Adobe)\n"; // A string identifying an issuer of character collections
959
+ $res.= "/Ordering (UCS)\n"; // A string that uniquely names a character collection issued by a specific registry
960
+ $res.= "/Supplement 0\n"; // The supplement number of the character collection.
961
+ $res.= ">>";
962
+ $this->objects[$cidSystemInfoId]['c'] = $res;
963
+
964
+ // and a CID to GID map
965
+ $cidToGidMapId = ++$this->numObj;
966
+ $this->o_fontGIDtoCIDMap($cidToGidMapId, 'new', $options);
967
+ $this->objects[$id]['info']['cidToGidMap'] = $cidToGidMapId;
968
+ break;
969
+
970
+ case 'add':
971
+ foreach ($options as $k => $v) {
972
+ switch ($k) {
973
+ case 'BaseFont':
974
+ $o['info']['name'] = $v;
975
+ break;
976
+
977
+ case 'FirstChar':
978
+ case 'LastChar':
979
+ case 'MissingWidth':
980
+ case 'FontDescriptor':
981
+ case 'SubType':
982
+ $this->addMessage("o_fontDescendentCID $k : $v");
983
+ $o['info'][$k] = $v;
984
+ break;
985
+ }
986
+ }
987
+
988
+ // pass values down to cid to gid map
989
+ $this->o_fontGIDtoCIDMap($o['info']['cidToGidMap'], 'add', $options);
990
+ break;
991
+
992
+ case 'out':
993
+ $res = "\n$id 0 obj\n";
994
+ $res.= "<</Type /Font\n";
995
+ $res.= "/Subtype /CIDFontType2\n";
996
+ $res.= "/BaseFont /".$o['info']['name']."\n";
997
+ $res.= "/CIDSystemInfo ".$o['info']['cidSystemInfo']." 0 R\n";
998
+ // if (isset($o['info']['FirstChar'])) {
999
+ // $res.= "/FirstChar ".$o['info']['FirstChar']."\n";
1000
+ // }
1001
+
1002
+ // if (isset($o['info']['LastChar'])) {
1003
+ // $res.= "/LastChar ".$o['info']['LastChar']."\n";
1004
+ // }
1005
+ if (isset($o['info']['FontDescriptor'])) {
1006
+ $res.= "/FontDescriptor ".$o['info']['FontDescriptor']." 0 R\n";
1007
+ }
1008
+
1009
+ if (isset($o['info']['MissingWidth'])) {
1010
+ $res.= "/DW ".$o['info']['MissingWidth']."\n";
1011
+ }
1012
+
1013
+ if (isset($o['info']['fontFileName']) && isset($this->fonts[$o['info']['fontFileName']]['CIDWidths'])) {
1014
+ $cid_widths = &$this->fonts[$o['info']['fontFileName']]['CIDWidths'];
1015
+ $w = '';
1016
+ foreach ($cid_widths as $cid => $width) {
1017
+ $w .= "$cid [$width] ";
1018
+ }
1019
+ $res.= "/W [$w]\n";
1020
+ }
1021
+
1022
+ $res.= "/CIDToGIDMap ".$o['info']['cidToGidMap']." 0 R\n";
1023
+ $res.= ">>\n";
1024
+ $res.= "endobj";
1025
+
1026
+ return $res;
1027
+ }
1028
+ }
1029
+
1030
+ /**
1031
+ * a font glyph to character map, needed for unicode fonts
1032
+ */
1033
+ protected function o_fontGIDtoCIDMap($id, $action, $options = '') {
1034
+ if ($action !== 'new') {
1035
+ $o = & $this->objects[$id];
1036
+ }
1037
+
1038
+ switch ($action) {
1039
+ case 'new':
1040
+ $this->objects[$id] = array('t'=>'fontGIDtoCIDMap', 'info'=>$options);
1041
+ break;
1042
+
1043
+ case 'out':
1044
+ $res = "\n$id 0 obj\n";
1045
+ $fontFileName = $o['info']['fontFileName'];
1046
+ $tmp = $this->fonts[$fontFileName]['CIDtoGID'] = base64_decode($this->fonts[$fontFileName]['CIDtoGID']);
1047
+
1048
+ $compressed = isset($this->fonts[$fontFileName]['CIDtoGID_Compressed']) &&
1049
+ $this->fonts[$fontFileName]['CIDtoGID_Compressed'];
1050
+
1051
+ if (!$compressed && isset($o['raw'])) {
1052
+ $res.= $tmp;
1053
+ } else {
1054
+ $res.= "<<";
1055
+
1056
+ if (!$compressed && $this->compressionReady && $this->options['compression']) {
1057
+ // then implement ZLIB based compression on this content stream
1058
+ $compressed = true;
1059
+ $tmp = gzcompress($tmp, 6);
1060
+ }
1061
+ if ($compressed) {
1062
+ $res.= "\n/Filter /FlateDecode";
1063
+ }
1064
+
1065
+ $res.= "\n/Length ".mb_strlen($tmp, '8bit') .">>\nstream\n$tmp\nendstream";
1066
+ }
1067
+
1068
+ $res.= "\nendobj";
1069
+ return $res;
1070
+ }
1071
+ }
1072
+
1073
+ /**
1074
+ * the document procset, solves some problems with printing to old PS printers
1075
+ */
1076
+ protected function o_procset($id, $action, $options = '') {
1077
+ if ($action !== 'new') {
1078
+ $o = & $this->objects[$id];
1079
+ }
1080
+
1081
+ switch ($action) {
1082
+ case 'new':
1083
+ $this->objects[$id] = array('t'=>'procset', 'info'=>array('PDF'=>1, 'Text'=>1));
1084
+ $this->o_pages($this->currentNode, 'procset', $id);
1085
+ $this->procsetObjectId = $id;
1086
+ break;
1087
+
1088
+ case 'add':
1089
+ // this is to add new items to the procset list, despite the fact that this is considered
1090
+ // obselete, the items are required for printing to some postscript printers
1091
+ switch ($options) {
1092
+ case 'ImageB':
1093
+ case 'ImageC':
1094
+ case 'ImageI':
1095
+ $o['info'][$options] = 1;
1096
+ break;
1097
+ }
1098
+ break;
1099
+
1100
+ case 'out':
1101
+ $res = "\n$id 0 obj\n[";
1102
+ foreach ($o['info'] as $label=>$val) {
1103
+ $res.= "/$label ";
1104
+ }
1105
+ $res.= "]\nendobj";
1106
+ return $res;
1107
+ }
1108
+ }
1109
+
1110
+ /**
1111
+ * define the document information
1112
+ */
1113
+ protected function o_info($id, $action, $options = '') {
1114
+ if ($action !== 'new') {
1115
+ $o = & $this->objects[$id];
1116
+ }
1117
+
1118
+ switch ($action) {
1119
+ case 'new':
1120
+ $this->infoObject = $id;
1121
+ $date = 'D:'.@date('Ymd');
1122
+ $this->objects[$id] = array('t'=>'info', 'info'=>array('Creator'=>'R and OS php pdf writer, http://www.ros.co.nz', 'CreationDate'=>$date));
1123
+ break;
1124
+ case 'Title':
1125
+ case 'Author':
1126
+ case 'Subject':
1127
+ case 'Keywords':
1128
+ case 'Creator':
1129
+ case 'Producer':
1130
+ case 'CreationDate':
1131
+ case 'ModDate':
1132
+ case 'Trapped':
1133
+ $o['info'][$action] = $options;
1134
+ break;
1135
+
1136
+ case 'out':
1137
+ if ($this->encrypted) {
1138
+ $this->encryptInit($id);
1139
+ }
1140
+
1141
+ $res = "\n$id 0 obj\n<<\n";
1142
+ foreach ($o['info'] as $k=>$v) {
1143
+ $res.= "/$k (";
1144
+ // dates must be outputted as-is, without Unicode transformations
1145
+ $raw = ($k === 'CreationDate' || $k === 'ModDate');
1146
+ $c = $v;
1147
+
1148
+ if ($this->encrypted) {
1149
+ $c = $this->ARC4($c);
1150
+ }
1151
+
1152
+ $res.= ($raw) ? $c : $this->filterText($c);
1153
+ $res.= ")\n";
1154
+ }
1155
+
1156
+ $res.= ">>\nendobj";
1157
+ return $res;
1158
+ }
1159
+ }
1160
+
1161
+ /**
1162
+ * an action object, used to link to URLS initially
1163
+ */
1164
+ protected function o_action($id, $action, $options = '') {
1165
+ if ($action !== 'new') {
1166
+ $o = & $this->objects[$id];
1167
+ }
1168
+
1169
+ switch ($action) {
1170
+ case 'new':
1171
+ if (is_array($options)) {
1172
+ $this->objects[$id] = array('t'=>'action', 'info'=>$options, 'type'=>$options['type']);
1173
+ } else {
1174
+ // then assume a URI action
1175
+ $this->objects[$id] = array('t'=>'action', 'info'=>$options, 'type'=>'URI');
1176
+ }
1177
+ break;
1178
+
1179
+ case 'out':
1180
+ if ($this->encrypted) {
1181
+ $this->encryptInit($id);
1182
+ }
1183
+
1184
+ $res = "\n$id 0 obj\n<< /Type /Action";
1185
+ switch ($o['type']) {
1186
+ case 'ilink':
1187
+ if (!isset($this->destinations[(string)$o['info']['label']])) break;
1188
+
1189
+ // there will be an 'label' setting, this is the name of the destination
1190
+ $res.= "\n/S /GoTo\n/D ".$this->destinations[(string)$o['info']['label']]." 0 R";
1191
+ break;
1192
+
1193
+ case 'URI':
1194
+ $res.= "\n/S /URI\n/URI (";
1195
+ if ($this->encrypted) {
1196
+ $res.= $this->filterText($this->ARC4($o['info']), true, false);
1197
+ } else {
1198
+ $res.= $this->filterText($o['info'], true, false);
1199
+ }
1200
+
1201
+ $res.= ")";
1202
+ break;
1203
+ }
1204
+
1205
+ $res.= "\n>>\nendobj";
1206
+ return $res;
1207
+ }
1208
+ }
1209
+
1210
+ /**
1211
+ * an annotation object, this will add an annotation to the current page.
1212
+ * initially will support just link annotations
1213
+ */
1214
+ protected function o_annotation($id, $action, $options = '') {
1215
+ if ($action !== 'new') {
1216
+ $o = & $this->objects[$id];
1217
+ }
1218
+
1219
+ switch ($action) {
1220
+ case 'new':
1221
+ // add the annotation to the current page
1222
+ $pageId = $this->currentPage;
1223
+ $this->o_page($pageId, 'annot', $id);
1224
+
1225
+ // and add the action object which is going to be required
1226
+ switch ($options['type']) {
1227
+ case 'link':
1228
+ $this->objects[$id] = array('t'=>'annotation', 'info'=>$options);
1229
+ $this->numObj++;
1230
+ $this->o_action($this->numObj, 'new', $options['url']);
1231
+ $this->objects[$id]['info']['actionId'] = $this->numObj;
1232
+ break;
1233
+
1234
+ case 'ilink':
1235
+ // this is to a named internal link
1236
+ $label = $options['label'];
1237
+ $this->objects[$id] = array('t'=>'annotation', 'info'=>$options);
1238
+ $this->numObj++;
1239
+ $this->o_action($this->numObj, 'new', array('type'=>'ilink', 'label'=>$label));
1240
+ $this->objects[$id]['info']['actionId'] = $this->numObj;
1241
+ break;
1242
+ }
1243
+ break;
1244
+
1245
+ case 'out':
1246
+ $res = "\n$id 0 obj\n<< /Type /Annot";
1247
+ switch ($o['info']['type']) {
1248
+ case 'link':
1249
+ case 'ilink':
1250
+ $res.= "\n/Subtype /Link";
1251
+ break;
1252
+ }
1253
+ $res.= "\n/A ".$o['info']['actionId']." 0 R";
1254
+ $res.= "\n/Border [0 0 0]";
1255
+ $res.= "\n/H /I";
1256
+ $res.= "\n/Rect [ ";
1257
+
1258
+ foreach($o['info']['rect'] as $v) {
1259
+ $res.= sprintf("%.4F ", $v);
1260
+ }
1261
+
1262
+ $res.= "]";
1263
+ $res.= "\n>>\nendobj";
1264
+ return $res;
1265
+ }
1266
+ }
1267
+
1268
+ /**
1269
+ * a page object, it also creates a contents object to hold its contents
1270
+ */
1271
+ protected function o_page($id, $action, $options = '') {
1272
+ if ($action !== 'new') {
1273
+ $o = & $this->objects[$id];
1274
+ }
1275
+
1276
+ switch ($action) {
1277
+ case 'new':
1278
+ $this->numPages++;
1279
+ $this->objects[$id] = array('t'=>'page', 'info'=>array('parent'=>$this->currentNode, 'pageNum'=>$this->numPages));
1280
+
1281
+ if (is_array($options)) {
1282
+ // then this must be a page insertion, array should contain 'rid','pos'=[before|after]
1283
+ $options['id'] = $id;
1284
+ $this->o_pages($this->currentNode, 'page', $options);
1285
+ } else {
1286
+ $this->o_pages($this->currentNode, 'page', $id);
1287
+ }
1288
+
1289
+ $this->currentPage = $id;
1290
+ //make a contents object to go with this page
1291
+ $this->numObj++;
1292
+ $this->o_contents($this->numObj, 'new', $id);
1293
+ $this->currentContents = $this->numObj;
1294
+ $this->objects[$id]['info']['contents'] = array();
1295
+ $this->objects[$id]['info']['contents'][] = $this->numObj;
1296
+
1297
+ $match = ($this->numPages%2 ? 'odd' : 'even');
1298
+ foreach($this->addLooseObjects as $oId=>$target) {
1299
+ if ($target === 'all' || $match === $target) {
1300
+ $this->objects[$id]['info']['contents'][] = $oId;
1301
+ }
1302
+ }
1303
+ break;
1304
+
1305
+ case 'content':
1306
+ $o['info']['contents'][] = $options;
1307
+ break;
1308
+
1309
+ case 'annot':
1310
+ // add an annotation to this page
1311
+ if (!isset($o['info']['annot'])) {
1312
+ $o['info']['annot'] = array();
1313
+ }
1314
+
1315
+ // $options should contain the id of the annotation dictionary
1316
+ $o['info']['annot'][] = $options;
1317
+ break;
1318
+
1319
+ case 'out':
1320
+ $res = "\n$id 0 obj\n<< /Type /Page";
1321
+ $res.= "\n/Parent ".$o['info']['parent']." 0 R";
1322
+
1323
+ if (isset($o['info']['annot'])) {
1324
+ $res.= "\n/Annots [";
1325
+ foreach($o['info']['annot'] as $aId) {
1326
+ $res.= " $aId 0 R";
1327
+ }
1328
+ $res.= " ]";
1329
+ }
1330
+
1331
+ $count = count($o['info']['contents']);
1332
+ if ($count == 1) {
1333
+ $res.= "\n/Contents ".$o['info']['contents'][0]." 0 R";
1334
+ } else if ($count>1) {
1335
+ $res.= "\n/Contents [\n";
1336
+
1337
+ // reverse the page contents so added objects are below normal content
1338
+ //foreach (array_reverse($o['info']['contents']) as $cId) {
1339
+ // Back to normal now that I've got transparency working --Benj
1340
+ foreach ($o['info']['contents'] as $cId) {
1341
+ $res.= "$cId 0 R\n";
1342
+ }
1343
+ $res.= "]";
1344
+ }
1345
+
1346
+ $res.= "\n>>\nendobj";
1347
+ return $res;
1348
+ }
1349
+ }
1350
+
1351
+ /**
1352
+ * the contents objects hold all of the content which appears on pages
1353
+ */
1354
+ protected function o_contents($id, $action, $options = '') {
1355
+ if ($action !== 'new') {
1356
+ $o = & $this->objects[$id];
1357
+ }
1358
+
1359
+ switch ($action) {
1360
+ case 'new':
1361
+ $this->objects[$id] = array('t'=>'contents', 'c'=>'', 'info'=>array());
1362
+ if (mb_strlen($options, '8bit') && intval($options)) {
1363
+ // then this contents is the primary for a page
1364
+ $this->objects[$id]['onPage'] = $options;
1365
+ } else if ($options === 'raw') {
1366
+ // then this page contains some other type of system object
1367
+ $this->objects[$id]['raw'] = 1;
1368
+ }
1369
+ break;
1370
+
1371
+ case 'add':
1372
+ // add more options to the decleration
1373
+ foreach ($options as $k=>$v) {
1374
+ $o['info'][$k] = $v;
1375
+ }
1376
+
1377
+ case 'out':
1378
+ $tmp = $o['c'];
1379
+ $res = "\n$id 0 obj\n";
1380
+
1381
+ if (isset($this->objects[$id]['raw'])) {
1382
+ $res.= $tmp;
1383
+ } else {
1384
+ $res.= "<<";
1385
+ if ($this->compressionReady && $this->options['compression']) {
1386
+ // then implement ZLIB based compression on this content stream
1387
+ $res.= " /Filter /FlateDecode";
1388
+ $tmp = gzcompress($tmp, 6);
1389
+ }
1390
+
1391
+ if ($this->encrypted) {
1392
+ $this->encryptInit($id);
1393
+ $tmp = $this->ARC4($tmp);
1394
+ }
1395
+
1396
+ foreach($o['info'] as $k=>$v) {
1397
+ $res.= "\n/$k $v";
1398
+ }
1399
+
1400
+ $res.= "\n/Length ".mb_strlen($tmp, '8bit') ." >>\nstream\n$tmp\nendstream";
1401
+ }
1402
+
1403
+ $res.= "\nendobj";
1404
+ return $res;
1405
+ }
1406
+ }
1407
+
1408
+ protected function o_embedjs($id, $action, $code = '') {
1409
+ if ($action !== 'new') {
1410
+ $o = & $this->objects[$id];
1411
+ }
1412
+
1413
+ switch ($action) {
1414
+ case 'new':
1415
+ $this->objects[$id] = array('t'=>'embedjs', 'info'=>array(
1416
+ 'Names' => '[(EmbeddedJS) '.($id+1).' 0 R]'
1417
+ ));
1418
+ break;
1419
+
1420
+ case 'out':
1421
+ $res = "\n$id 0 obj\n<< ";
1422
+ foreach($o['info'] as $k=>$v) {
1423
+ $res.= "\n/$k $v";
1424
+ }
1425
+ $res.= "\n>>\nendobj";
1426
+ return $res;
1427
+ }
1428
+ }
1429
+
1430
+ protected function o_javascript($id, $action, $code = '') {
1431
+ if ($action !== 'new') {
1432
+ $o = & $this->objects[$id];
1433
+ }
1434
+
1435
+ switch ($action) {
1436
+ case 'new':
1437
+ $this->objects[$id] = array('t'=>'javascript', 'info'=>array(
1438
+ 'S' => '/JavaScript',
1439
+ 'JS' => '('.$this->filterText($code).')',
1440
+ ));
1441
+ break;
1442
+
1443
+ case 'out':
1444
+ $res = "\n$id 0 obj\n<< ";
1445
+ foreach($o['info'] as $k=>$v) {
1446
+ $res.= "\n/$k $v";
1447
+ }
1448
+ $res.= "\n>>\nendobj";
1449
+ return $res;
1450
+ }
1451
+ }
1452
+
1453
+ /**
1454
+ * an image object, will be an XObject in the document, includes description and data
1455
+ */
1456
+ protected function o_image($id, $action, $options = '') {
1457
+ if ($action !== 'new') {
1458
+ $o = & $this->objects[$id];
1459
+ }
1460
+
1461
+ switch ($action) {
1462
+ case 'new':
1463
+ // make the new object
1464
+ $this->objects[$id] = array('t'=>'image', 'data'=>&$options['data'], 'info'=>array());
1465
+
1466
+ $info =& $this->objects[$id]['info'];
1467
+
1468
+ $info['Type'] = '/XObject';
1469
+ $info['Subtype'] = '/Image';
1470
+ $info['Width'] = $options['iw'];
1471
+ $info['Height'] = $options['ih'];
1472
+
1473
+ if (isset($options['masked']) && $options['masked']) {
1474
+ $info['SMask'] = ($this->numObj-1).' 0 R';
1475
+ }
1476
+
1477
+ if (!isset($options['type']) || $options['type'] === 'jpg') {
1478
+ if (!isset($options['channels'])) {
1479
+ $options['channels'] = 3;
1480
+ }
1481
+
1482
+ switch ($options['channels']) {
1483
+ case 1: $info['ColorSpace'] = '/DeviceGray'; break;
1484
+ case 4: $info['ColorSpace'] = '/DeviceCMYK'; break;
1485
+ default: $info['ColorSpace'] = '/DeviceRGB'; break;
1486
+ }
1487
+
1488
+ if ($info['ColorSpace'] === '/DeviceCMYK') {
1489
+ $info['Decode'] = '[1 0 1 0 1 0 1 0]';
1490
+ }
1491
+
1492
+ $info['Filter'] = '/DCTDecode';
1493
+ $info['BitsPerComponent'] = 8;
1494
+ }
1495
+
1496
+ else if ($options['type'] === 'png') {
1497
+ $info['Filter'] = '/FlateDecode';
1498
+ $info['DecodeParms'] = '<< /Predictor 15 /Colors '.$options['ncolor'].' /Columns '.$options['iw'].' /BitsPerComponent '.$options['bitsPerComponent'].'>>';
1499
+
1500
+ if ($options['isMask']) {
1501
+ $info['ColorSpace'] = '/DeviceGray';
1502
+ }
1503
+ else {
1504
+ if (mb_strlen($options['pdata'], '8bit')) {
1505
+ $tmp = ' [ /Indexed /DeviceRGB '.(mb_strlen($options['pdata'], '8bit') /3-1) .' ';
1506
+ $this->numObj++;
1507
+ $this->o_contents($this->numObj, 'new');
1508
+ $this->objects[$this->numObj]['c'] = $options['pdata'];
1509
+ $tmp.= $this->numObj.' 0 R';
1510
+ $tmp.= ' ]';
1511
+ $info['ColorSpace'] = $tmp;
1512
+
1513
+ if (isset($options['transparency'])) {
1514
+ $transparency = $options['transparency'];
1515
+ switch ($transparency['type']) {
1516
+ case 'indexed':
1517
+ $tmp = ' [ '.$transparency['data'].' '.$transparency['data'].'] ';
1518
+ $info['Mask'] = $tmp;
1519
+ break;
1520
+
1521
+ case 'color-key':
1522
+ $tmp = ' [ '.
1523
+ $transparency['r'] . ' ' . $transparency['r'] .
1524
+ $transparency['g'] . ' ' . $transparency['g'] .
1525
+ $transparency['b'] . ' ' . $transparency['b'] .
1526
+ ' ] ';
1527
+ $info['Mask'] = $tmp;
1528
+ break;
1529
+ }
1530
+ }
1531
+ } else {
1532
+ if (isset($options['transparency'])) {
1533
+ $transparency = $options['transparency'];
1534
+
1535
+ switch ($transparency['type']) {
1536
+ case 'indexed':
1537
+ $tmp = ' [ '.$transparency['data'].' '.$transparency['data'].'] ';
1538
+ $info['Mask'] = $tmp;
1539
+ break;
1540
+
1541
+ case 'color-key':
1542
+ $tmp = ' [ '.
1543
+ $transparency['r'] . ' ' . $transparency['r'] . ' ' .
1544
+ $transparency['g'] . ' ' . $transparency['g'] . ' ' .
1545
+ $transparency['b'] . ' ' . $transparency['b'] .
1546
+ ' ] ';
1547
+ $info['Mask'] = $tmp;
1548
+ break;
1549
+ }
1550
+ }
1551
+ $info['ColorSpace'] = '/'.$options['color'];
1552
+ }
1553
+ }
1554
+
1555
+ $info['BitsPerComponent'] = $options['bitsPerComponent'];
1556
+ }
1557
+
1558
+ // assign it a place in the named resource dictionary as an external object, according to
1559
+ // the label passed in with it.
1560
+ $this->o_pages($this->currentNode, 'xObject', array('label'=>$options['label'], 'objNum'=>$id));
1561
+
1562
+ // also make sure that we have the right procset object for it.
1563
+ $this->o_procset($this->procsetObjectId, 'add', 'ImageC');
1564
+ break;
1565
+
1566
+ case 'out':
1567
+ $tmp = &$o['data'];
1568
+ $res = "\n$id 0 obj\n<<";
1569
+
1570
+ foreach($o['info'] as $k=>$v) {
1571
+ $res.= "\n/$k $v";
1572
+ }
1573
+
1574
+ if ($this->encrypted) {
1575
+ $this->encryptInit($id);
1576
+ $tmp = $this->ARC4($tmp);
1577
+ }
1578
+
1579
+ $res.= "\n/Length ".mb_strlen($tmp, '8bit') .">>\nstream\n$tmp\nendstream\nendobj";
1580
+
1581
+ return $res;
1582
+ }
1583
+ }
1584
+
1585
+ /**
1586
+ * graphics state object
1587
+ */
1588
+ protected function o_extGState($id, $action, $options = "") {
1589
+ static $valid_params = array("LW", "LC", "LC", "LJ", "ML",
1590
+ "D", "RI", "OP", "op", "OPM",
1591
+ "Font", "BG", "BG2", "UCR",
1592
+ "TR", "TR2", "HT", "FL",
1593
+ "SM", "SA", "BM", "SMask",
1594
+ "CA", "ca", "AIS", "TK");
1595
+
1596
+ if ($action !== "new") {
1597
+ $o = & $this->objects[$id];
1598
+ }
1599
+
1600
+ switch ($action) {
1601
+ case "new":
1602
+ $this->objects[$id] = array('t' => 'extGState', 'info' => $options);
1603
+
1604
+ // Tell the pages about the new resource
1605
+ $this->numStates++;
1606
+ $this->o_pages($this->currentNode, 'extGState', array("objNum" => $id, "stateNum" => $this->numStates));
1607
+ break;
1608
+
1609
+ case "out":
1610
+ $res = "\n$id 0 obj\n<< /Type /ExtGState\n";
1611
+
1612
+ foreach ($o["info"] as $k => $v) {
1613
+ if ( !in_array($k, $valid_params))
1614
+ continue;
1615
+ $res.= "/$k $v\n";
1616
+ }
1617
+
1618
+ $res.= ">>\nendobj";
1619
+ return $res;
1620
+ }
1621
+ }
1622
+
1623
+ /**
1624
+ * encryption object.
1625
+ */
1626
+ protected function o_encryption($id, $action, $options = '') {
1627
+ if ($action !== 'new') {
1628
+ $o = & $this->objects[$id];
1629
+ }
1630
+
1631
+ switch ($action) {
1632
+ case 'new':
1633
+ // make the new object
1634
+ $this->objects[$id] = array('t'=>'encryption', 'info'=>$options);
1635
+ $this->arc4_objnum = $id;
1636
+
1637
+ // figure out the additional paramaters required
1638
+ $pad = chr(0x28) .chr(0xBF) .chr(0x4E) .chr(0x5E) .chr(0x4E) .chr(0x75) .chr(0x8A) .chr(0x41)
1639
+ .chr(0x64) .chr(0x00) .chr(0x4E) .chr(0x56) .chr(0xFF) .chr(0xFA) .chr(0x01) .chr(0x08)
1640
+ .chr(0x2E) .chr(0x2E) .chr(0x00) .chr(0xB6) .chr(0xD0) .chr(0x68) .chr(0x3E) .chr(0x80)
1641
+ .chr(0x2F) .chr(0x0C) .chr(0xA9) .chr(0xFE) .chr(0x64) .chr(0x53) .chr(0x69) .chr(0x7A);
1642
+
1643
+ $len = mb_strlen($options['owner'], '8bit');
1644
+
1645
+ if ($len>32) {
1646
+ $owner = substr($options['owner'], 0, 32);
1647
+ } else if ($len<32) {
1648
+ $owner = $options['owner'].substr($pad, 0, 32-$len);
1649
+ } else {
1650
+ $owner = $options['owner'];
1651
+ }
1652
+
1653
+ $len = mb_strlen($options['user'], '8bit');
1654
+ if ($len>32) {
1655
+ $user = substr($options['user'], 0, 32);
1656
+ } else if ($len<32) {
1657
+ $user = $options['user'].substr($pad, 0, 32-$len);
1658
+ } else {
1659
+ $user = $options['user'];
1660
+ }
1661
+
1662
+ $tmp = $this->md5_16($owner);
1663
+ $okey = substr($tmp, 0, 5);
1664
+ $this->ARC4_init($okey);
1665
+ $ovalue = $this->ARC4($user);
1666
+ $this->objects[$id]['info']['O'] = $ovalue;
1667
+
1668
+ // now make the u value, phew.
1669
+ $tmp = $this->md5_16($user.$ovalue.chr($options['p']) .chr(255) .chr(255) .chr(255) .$this->fileIdentifier);
1670
+
1671
+ $ukey = substr($tmp, 0, 5);
1672
+ $this->ARC4_init($ukey);
1673
+ $this->encryptionKey = $ukey;
1674
+ $this->encrypted = true;
1675
+ $uvalue = $this->ARC4($pad);
1676
+ $this->objects[$id]['info']['U'] = $uvalue;
1677
+ $this->encryptionKey = $ukey;
1678
+ // initialize the arc4 array
1679
+ break;
1680
+
1681
+ case 'out':
1682
+ $res = "\n$id 0 obj\n<<";
1683
+ $res.= "\n/Filter /Standard";
1684
+ $res.= "\n/V 1";
1685
+ $res.= "\n/R 2";
1686
+ $res.= "\n/O (".$this->filterText($o['info']['O'], true, false) .')';
1687
+ $res.= "\n/U (".$this->filterText($o['info']['U'], true, false) .')';
1688
+ // and the p-value needs to be converted to account for the twos-complement approach
1689
+ $o['info']['p'] = (($o['info']['p']^255) +1) *-1;
1690
+ $res.= "\n/P ".($o['info']['p']);
1691
+ $res.= "\n>>\nendobj";
1692
+ return $res;
1693
+ }
1694
+ }
1695
+
1696
+ /**
1697
+ * ARC4 functions
1698
+ * A series of function to implement ARC4 encoding in PHP
1699
+ */
1700
+
1701
+ /**
1702
+ * calculate the 16 byte version of the 128 bit md5 digest of the string
1703
+ */
1704
+ function md5_16($string) {
1705
+ $tmp = md5($string);
1706
+ $out = '';
1707
+ for ($i = 0;$i <= 30;$i = $i+2) {
1708
+ $out.= chr(hexdec(substr($tmp, $i, 2)));
1709
+ }
1710
+ return $out;
1711
+ }
1712
+
1713
+ /**
1714
+ * initialize the encryption for processing a particular object
1715
+ */
1716
+ function encryptInit($id) {
1717
+ $tmp = $this->encryptionKey;
1718
+ $hex = dechex($id);
1719
+ if (mb_strlen($hex, '8bit') <6) {
1720
+ $hex = substr('000000', 0, 6-mb_strlen($hex, '8bit')) .$hex;
1721
+ }
1722
+ $tmp.= chr(hexdec(substr($hex, 4, 2))) .chr(hexdec(substr($hex, 2, 2))) .chr(hexdec(substr($hex, 0, 2))) .chr(0) .chr(0);
1723
+ $key = $this->md5_16($tmp);
1724
+ $this->ARC4_init(substr($key, 0, 10));
1725
+ }
1726
+
1727
+ /**
1728
+ * initialize the ARC4 encryption
1729
+ */
1730
+ function ARC4_init($key = '') {
1731
+ $this->arc4 = '';
1732
+
1733
+ // setup the control array
1734
+ if (mb_strlen($key, '8bit') == 0) {
1735
+ return;
1736
+ }
1737
+
1738
+ $k = '';
1739
+ while (mb_strlen($k, '8bit') <256) {
1740
+ $k.= $key;
1741
+ }
1742
+
1743
+ $k = substr($k, 0, 256);
1744
+ for ($i = 0;$i<256;$i++) {
1745
+ $this->arc4.= chr($i);
1746
+ }
1747
+
1748
+ $j = 0;
1749
+
1750
+ for ($i = 0;$i<256;$i++) {
1751
+ $t = $this->arc4[$i];
1752
+ $j = ($j + ord($t) + ord($k[$i])) %256;
1753
+ $this->arc4[$i] = $this->arc4[$j];
1754
+ $this->arc4[$j] = $t;
1755
+ }
1756
+ }
1757
+
1758
+ /**
1759
+ * ARC4 encrypt a text string
1760
+ */
1761
+ function ARC4($text) {
1762
+ $len = mb_strlen($text, '8bit');
1763
+ $a = 0;
1764
+ $b = 0;
1765
+ $c = $this->arc4;
1766
+ $out = '';
1767
+ for ($i = 0;$i<$len;$i++) {
1768
+ $a = ($a+1) %256;
1769
+ $t = $c[$a];
1770
+ $b = ($b+ord($t)) %256;
1771
+ $c[$a] = $c[$b];
1772
+ $c[$b] = $t;
1773
+ $k = ord($c[(ord($c[$a]) +ord($c[$b])) %256]);
1774
+ $out.= chr(ord($text[$i]) ^ $k);
1775
+ }
1776
+ return $out;
1777
+ }
1778
+
1779
+ /**
1780
+ * functions which can be called to adjust or add to the document
1781
+ */
1782
+
1783
+ /**
1784
+ * add a link in the document to an external URL
1785
+ */
1786
+ function addLink($url, $x0, $y0, $x1, $y1) {
1787
+ $this->numObj++;
1788
+ $info = array('type'=>'link', 'url'=>$url, 'rect'=>array($x0, $y0, $x1, $y1));
1789
+ $this->o_annotation($this->numObj, 'new', $info);
1790
+ }
1791
+
1792
+ /**
1793
+ * add a link in the document to an internal destination (ie. within the document)
1794
+ */
1795
+ function addInternalLink($label, $x0, $y0, $x1, $y1) {
1796
+ $this->numObj++;
1797
+ $info = array('type'=>'ilink', 'label'=>$label, 'rect'=>array($x0, $y0, $x1, $y1));
1798
+ $this->o_annotation($this->numObj, 'new', $info);
1799
+ }
1800
+
1801
+ /**
1802
+ * set the encryption of the document
1803
+ * can be used to turn it on and/or set the passwords which it will have.
1804
+ * also the functions that the user will have are set here, such as print, modify, add
1805
+ */
1806
+ function setEncryption($userPass = '', $ownerPass = '', $pc = array()) {
1807
+ $p = bindec("11000000");
1808
+
1809
+ $options = array('print'=>4, 'modify'=>8, 'copy'=>16, 'add'=>32);
1810
+
1811
+ foreach($pc as $k=>$v) {
1812
+ if ($v && isset($options[$k])) {
1813
+ $p+= $options[$k];
1814
+ } else if (isset($options[$v])) {
1815
+ $p+= $options[$v];
1816
+ }
1817
+ }
1818
+
1819
+ // implement encryption on the document
1820
+ if ($this->arc4_objnum == 0) {
1821
+ // then the block does not exist already, add it.
1822
+ $this->numObj++;
1823
+ if (mb_strlen($ownerPass) == 0) {
1824
+ $ownerPass = $userPass;
1825
+ }
1826
+
1827
+ $this->o_encryption($this->numObj, 'new', array('user'=>$userPass, 'owner'=>$ownerPass, 'p'=>$p));
1828
+ }
1829
+ }
1830
+
1831
+ /**
1832
+ * should be used for internal checks, not implemented as yet
1833
+ */
1834
+ function checkAllHere() {
1835
+ }
1836
+
1837
+ /**
1838
+ * return the pdf stream as a string returned from the function
1839
+ */
1840
+ function output($debug = false) {
1841
+ if ($debug) {
1842
+ // turn compression off
1843
+ $this->options['compression'] = false;
1844
+ }
1845
+
1846
+ if ($this->javascript) {
1847
+ $this->numObj++;
1848
+
1849
+ $js_id = $this->numObj;
1850
+ $this->o_embedjs($js_id, 'new');
1851
+ $this->o_javascript(++$this->numObj, 'new', $this->javascript);
1852
+
1853
+ $id = $this->catalogId;
1854
+
1855
+ $this->o_catalog($id, 'javascript', $js_id);
1856
+ }
1857
+
1858
+ if ($this->arc4_objnum) {
1859
+ $this->ARC4_init($this->encryptionKey);
1860
+ }
1861
+
1862
+ $this->checkAllHere();
1863
+
1864
+
1865
+ $xref = array();
1866
+ $content = '%PDF-1.3';
1867
+ $pos = mb_strlen($content, '8bit');
1868
+
1869
+ foreach($this->objects as $k=>$v) {
1870
+ $tmp = 'o_'.$v['t'];
1871
+ $cont = $this->$tmp($k, 'out');
1872
+ $content.= $cont;
1873
+ $xref[] = $pos;
1874
+ $pos+= mb_strlen($cont, '8bit');
1875
+ }
1876
+
1877
+ $content.= "\nxref\n0 ".(count($xref) +1) ."\n0000000000 65535 f \n";
1878
+
1879
+ foreach($xref as $p) {
1880
+ $content.= str_pad($p, 10, "0", STR_PAD_LEFT) . " 00000 n \n";
1881
+ }
1882
+
1883
+ $content.= "trailer\n<<\n/Size ".(count($xref) +1) ."\n/Root 1 0 R\n/Info $this->infoObject 0 R\n";
1884
+
1885
+ // if encryption has been applied to this document then add the marker for this dictionary
1886
+ if ($this->arc4_objnum > 0) {
1887
+ $content.= "/Encrypt $this->arc4_objnum 0 R\n";
1888
+ }
1889
+
1890
+ if (mb_strlen($this->fileIdentifier, '8bit')) {
1891
+ $content.= "/ID[<$this->fileIdentifier><$this->fileIdentifier>]\n";
1892
+ }
1893
+
1894
+ $content.= ">>\nstartxref\n$pos\n%%EOF\n";
1895
+
1896
+ return $content;
1897
+ }
1898
+
1899
+ /**
1900
+ * intialize a new document
1901
+ * if this is called on an existing document results may be unpredictable, but the existing document would be lost at minimum
1902
+ * this function is called automatically by the constructor function
1903
+ *
1904
+ * @access private
1905
+ */
1906
+ function newDocument($pageSize = array(0, 0, 612, 792)) {
1907
+ $this->numObj = 0;
1908
+ $this->objects = array();
1909
+
1910
+ $this->numObj++;
1911
+ $this->o_catalog($this->numObj, 'new');
1912
+
1913
+ $this->numObj++;
1914
+ $this->o_outlines($this->numObj, 'new');
1915
+
1916
+ $this->numObj++;
1917
+ $this->o_pages($this->numObj, 'new');
1918
+
1919
+ $this->o_pages($this->numObj, 'mediaBox', $pageSize);
1920
+ $this->currentNode = 3;
1921
+
1922
+ $this->numObj++;
1923
+ $this->o_procset($this->numObj, 'new');
1924
+
1925
+ $this->numObj++;
1926
+ $this->o_info($this->numObj, 'new');
1927
+
1928
+ $this->numObj++;
1929
+ $this->o_page($this->numObj, 'new');
1930
+
1931
+ // need to store the first page id as there is no way to get it to the user during
1932
+ // startup
1933
+ $this->firstPageId = $this->currentContents;
1934
+ }
1935
+
1936
+ /**
1937
+ * open the font file and return a php structure containing it.
1938
+ * first check if this one has been done before and saved in a form more suited to php
1939
+ * note that if a php serialized version does not exist it will try and make one, but will
1940
+ * require write access to the directory to do it... it is MUCH faster to have these serialized
1941
+ * files.
1942
+ *
1943
+ * @access private
1944
+ */
1945
+ function openFont($font) {
1946
+ // assume that $font contains the path and file but not the extension
1947
+ $pos = strrpos($font, '/');
1948
+
1949
+ if ($pos === false) {
1950
+ $dir = './';
1951
+ $name = $font;
1952
+ } else {
1953
+ $dir = substr($font, 0, $pos+1);
1954
+ $name = substr($font, $pos+1);
1955
+ }
1956
+
1957
+ $fontcache = $this->fontcache;
1958
+ if ($fontcache == '') {
1959
+ $fontcache = $dir;
1960
+ }
1961
+
1962
+ //$name filename without folder and extension of font metrics
1963
+ //$dir folder of font metrics
1964
+ //$fontcache folder of runtime created php serialized version of font metrics.
1965
+ // If this is not given, the same folder as the font metrics will be used.
1966
+ // Storing and reusing serialized versions improves speed much
1967
+
1968
+ $this->addMessage("openFont: $font - $name");
1969
+
1970
+ if ( !$this->isUnicode || in_array(mb_strtolower(basename($name)), self::$coreFonts) ) {
1971
+ $metrics_name = "$name.afm";
1972
+ }
1973
+ else {
1974
+ $metrics_name = "$name.ufm";
1975
+ }
1976
+
1977
+ $cache_name = "$metrics_name.php";
1978
+ $this->addMessage("metrics: $metrics_name, cache: $cache_name");
1979
+
1980
+ if (file_exists($fontcache . $cache_name)) {
1981
+ $this->addMessage("openFont: php file exists $fontcache$cache_name");
1982
+ $this->fonts[$font] = require($fontcache . $cache_name);
1983
+
1984
+ if (!isset($this->fonts[$font]['_version_']) || $this->fonts[$font]['_version_'] != $this->fontcacheVersion) {
1985
+ // if the font file is old, then clear it out and prepare for re-creation
1986
+ $this->addMessage('openFont: clear out, make way for new version.');
1987
+ $this->fonts[$font] = null;
1988
+ unset($this->fonts[$font]);
1989
+ }
1990
+ }
1991
+ else {
1992
+ $old_cache_name = "php_$metrics_name";
1993
+ if (file_exists($fontcache . $old_cache_name)) {
1994
+ $this->addMessage("openFont: php file doesn't exist $fontcache$cache_name, creating it from the old format");
1995
+ $old_cache = file_get_contents($fontcache . $old_cache_name);
1996
+ file_put_contents($fontcache . $cache_name, '<?php return ' . $old_cache . ';');
1997
+ return $this->openFont($font);
1998
+ }
1999
+ }
2000
+
2001
+ if (!isset($this->fonts[$font]) && file_exists($dir . $metrics_name)) {
2002
+ // then rebuild the php_<font>.afm file from the <font>.afm file
2003
+ $this->addMessage("openFont: build php file from $dir$metrics_name");
2004
+ $data = array();
2005
+
2006
+ // 20 => 'space'
2007
+ $data['codeToName'] = array();
2008
+
2009
+ // Since we're not going to enable Unicode for the core fonts we need to use a font-based
2010
+ // setting for Unicode support rather than a global setting.
2011
+ $data['isUnicode'] = (strtolower(substr($metrics_name, -3)) !== 'afm');
2012
+
2013
+ $cidtogid = '';
2014
+ if ($data['isUnicode']) {
2015
+ $cidtogid = str_pad('', 256*256*2, "\x00");
2016
+ }
2017
+
2018
+ $file = file($dir . $metrics_name);
2019
+
2020
+ foreach ($file as $rowA) {
2021
+ $row = trim($rowA);
2022
+ $pos = strpos($row, ' ');
2023
+
2024
+ if ($pos) {
2025
+ // then there must be some keyword
2026
+ $key = substr($row, 0, $pos);
2027
+ switch ($key) {
2028
+ case 'FontName':
2029
+ case 'FullName':
2030
+ case 'FamilyName':
2031
+ case 'PostScriptName':
2032
+ case 'Weight':
2033
+ case 'ItalicAngle':
2034
+ case 'IsFixedPitch':
2035
+ case 'CharacterSet':
2036
+ case 'UnderlinePosition':
2037
+ case 'UnderlineThickness':
2038
+ case 'Version':
2039
+ case 'EncodingScheme':
2040
+ case 'CapHeight':
2041
+ case 'XHeight':
2042
+ case 'Ascender':
2043
+ case 'Descender':
2044
+ case 'StdHW':
2045
+ case 'StdVW':
2046
+ case 'StartCharMetrics':
2047
+ case 'FontHeightOffset': // OAR - Added so we can offset the height calculation of a Windows font. Otherwise it's too big.
2048
+ $data[$key] = trim(substr($row, $pos));
2049
+ break;
2050
+
2051
+ case 'FontBBox':
2052
+ $data[$key] = explode(' ', trim(substr($row, $pos)));
2053
+ break;
2054
+
2055
+ //C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
2056
+ case 'C': // Found in AFM files
2057
+ $bits = explode(';', trim($row));
2058
+ $dtmp = array();
2059
+
2060
+ foreach($bits as $bit) {
2061
+ $bits2 = explode(' ', trim($bit));
2062
+ if (mb_strlen($bits2[0], '8bit') == 0) continue;
2063
+
2064
+ if (count($bits2) >2) {
2065
+ $dtmp[$bits2[0]] = array();
2066
+ for ($i = 1;$i<count($bits2);$i++) {
2067
+ $dtmp[$bits2[0]][] = $bits2[$i];
2068
+ }
2069
+ } else if (count($bits2) == 2) {
2070
+ $dtmp[$bits2[0]] = $bits2[1];
2071
+ }
2072
+ }
2073
+
2074
+ $c = (int)$dtmp['C'];
2075
+ $n = $dtmp['N'];
2076
+ $width = floatval($dtmp['WX']);
2077
+
2078
+ if ($c >= 0) {
2079
+ if ($c != hexdec($n)) {
2080
+ $data['codeToName'][$c] = $n;
2081
+ }
2082
+ $data['C'][$c] = $width;
2083
+ } else {
2084
+ $data['C'][$n] = $width;
2085
+ }
2086
+
2087
+ if (!isset($data['MissingWidth']) && $c == -1 && $n === '.notdef') {
2088
+ $data['MissingWidth'] = $width;
2089
+ }
2090
+
2091
+ break;
2092
+
2093
+ // U 827 ; WX 0 ; N squaresubnosp ; G 675 ;
2094
+ case 'U': // Found in UFM files
2095
+ if (!$data['isUnicode']) break;
2096
+
2097
+ $bits = explode(';', trim($row));
2098
+ $dtmp = array();
2099
+
2100
+ foreach($bits as $bit) {
2101
+ $bits2 = explode(' ', trim($bit));
2102
+ if (mb_strlen($bits2[0], '8bit') === 0) continue;
2103
+
2104
+ if (count($bits2) >2) {
2105
+ $dtmp[$bits2[0]] = array();
2106
+ for ($i = 1;$i<count($bits2);$i++) {
2107
+ $dtmp[$bits2[0]][] = $bits2[$i];
2108
+ }
2109
+ } else if (count($bits2) == 2) {
2110
+ $dtmp[$bits2[0]] = $bits2[1];
2111
+ }
2112
+ }
2113
+
2114
+ $c = (int)$dtmp['U'];
2115
+ $n = $dtmp['N'];
2116
+ $glyph = $dtmp['G'];
2117
+ $width = floatval($dtmp['WX']);
2118
+
2119
+ if ($c >= 0) {
2120
+ // Set values in CID to GID map
2121
+ if ($c >= 0 && $c < 0xFFFF && $glyph) {
2122
+ $cidtogid[$c*2] = chr($glyph >> 8);
2123
+ $cidtogid[$c*2 + 1] = chr($glyph & 0xFF);
2124
+ }
2125
+
2126
+ if ($c != hexdec($n)) {
2127
+ $data['codeToName'][$c] = $n;
2128
+ }
2129
+ $data['C'][$c] = $width;
2130
+ } else {
2131
+ $data['C'][$n] = $width;
2132
+ }
2133
+
2134
+ if (!isset($data['MissingWidth']) && $c == -1 && $n === '.notdef') {
2135
+ $data['MissingWidth'] = $width;
2136
+ }
2137
+
2138
+ break;
2139
+
2140
+ case 'KPX':
2141
+ break; // don't include them as they are not used yet
2142
+ //KPX Adieresis yacute -40
2143
+ $bits = explode(' ', trim($row));
2144
+ $data['KPX'][$bits[1]][$bits[2]] = $bits[3];
2145
+ break;
2146
+ }
2147
+ }
2148
+ }
2149
+
2150
+ // echo $cidtogid; die("CIDtoGID Displayed!");
2151
+ if ($this->compressionReady && $this->options['compression']) {
2152
+ // then implement ZLIB based compression on CIDtoGID string
2153
+ $data['CIDtoGID_Compressed'] = true;
2154
+ $cidtogid = gzcompress($cidtogid, 6);
2155
+ }
2156
+ $data['CIDtoGID'] = base64_encode($cidtogid);
2157
+ $data['_version_'] = $this->fontcacheVersion;
2158
+ $this->fonts[$font] = $data;
2159
+
2160
+ //Because of potential trouble with php safe mode, expect that the folder already exists.
2161
+ //If not existing, this will hit performance because of missing cached results.
2162
+ if ( is_dir(substr($fontcache,0,-1)) && is_writable(substr($fontcache,0,-1)) ) {
2163
+ file_put_contents($fontcache . $cache_name, '<?php return ' . var_export($data, true) . ';');
2164
+ }
2165
+ $data = null;
2166
+ }
2167
+
2168
+ if (!isset($this->fonts[$font])) {
2169
+ $this->addMessage("openFont: no font file found for $font. Do you need to run load_font.php?");
2170
+ //echo 'Font not Found '.$font;
2171
+ }
2172
+
2173
+ //pre_r($this->messages);
2174
+ }
2175
+
2176
+ /**
2177
+ * if the font is not loaded then load it and make the required object
2178
+ * else just make it the current font
2179
+ * the encoding array can contain 'encoding'=> 'none','WinAnsiEncoding','MacRomanEncoding' or 'MacExpertEncoding'
2180
+ * note that encoding='none' will need to be used for symbolic fonts
2181
+ * and 'differences' => an array of mappings between numbers 0->255 and character names.
2182
+ *
2183
+ */
2184
+ function selectFont($fontName, $encoding = '', $set = true) {
2185
+ $ext = substr($fontName, -4);
2186
+ if ($ext === '.afm' || $ext === '.ufm') {
2187
+ $fontName = substr($fontName, 0, mb_strlen($fontName)-4);
2188
+ }
2189
+
2190
+ if (!isset($this->fonts[$fontName])) {
2191
+ $this->addMessage("selectFont: selecting - $fontName - $encoding, $set");
2192
+
2193
+ // load the file
2194
+ $this->openFont($fontName);
2195
+
2196
+ if (isset($this->fonts[$fontName])) {
2197
+ $this->numObj++;
2198
+ $this->numFonts++;
2199
+
2200
+ $font = &$this->fonts[$fontName];
2201
+
2202
+ //$this->numFonts = md5($fontName);
2203
+ $pos = strrpos($fontName, '/');
2204
+ // $dir = substr($fontName,0,$pos+1);
2205
+ $name = substr($fontName, $pos+1);
2206
+ $options = array('name' => $name, 'fontFileName' => $fontName);
2207
+
2208
+ if (is_array($encoding)) {
2209
+ // then encoding and differences might be set
2210
+ if (isset($encoding['encoding'])) {
2211
+ $options['encoding'] = $encoding['encoding'];
2212
+ }
2213
+
2214
+ if (isset($encoding['differences'])) {
2215
+ $options['differences'] = $encoding['differences'];
2216
+ }
2217
+ } else if (mb_strlen($encoding, '8bit')) {
2218
+ // then perhaps only the encoding has been set
2219
+ $options['encoding'] = $encoding;
2220
+ }
2221
+
2222
+ $fontObj = $this->numObj;
2223
+ $this->o_font($this->numObj, 'new', $options);
2224
+ $font['fontNum'] = $this->numFonts;
2225
+
2226
+ // if this is a '.afm' font, and there is a '.pfa' file to go with it ( as there
2227
+ // should be for all non-basic fonts), then load it into an object and put the
2228
+ // references into the font object
2229
+ $basefile = $fontName;
2230
+
2231
+ $fbtype = '';
2232
+ if (file_exists("$basefile.pfb")) {
2233
+ $fbtype = 'pfb';
2234
+ }
2235
+ elseif (file_exists("$basefile.ttf")) {
2236
+ $fbtype = 'ttf';
2237
+ }
2238
+
2239
+ $fbfile = "$basefile.$fbtype";
2240
+
2241
+ // $pfbfile = substr($fontName,0,strlen($fontName)-4).'.pfb';
2242
+ // $ttffile = substr($fontName,0,strlen($fontName)-4).'.ttf';
2243
+ $this->addMessage('selectFont: checking for - '.$fbfile);
2244
+
2245
+ // OAR - I don't understand this old check
2246
+ // if (substr($fontName, -4) === '.afm' && strlen($fbtype)) {
2247
+ if ($fbtype) {
2248
+ $adobeFontName = isset($font['PostScriptName']) ? $font['PostScriptName'] : $font['FontName'];
2249
+ // $fontObj = $this->numObj;
2250
+ $this->addMessage("selectFont: adding font file - $fbfile - $adobeFontName");
2251
+
2252
+ // find the array of font widths, and put that into an object.
2253
+ $firstChar = -1;
2254
+ $lastChar = 0;
2255
+ $widths = array();
2256
+ $cid_widths = array();
2257
+
2258
+ foreach ($font['C'] as $num => $d) {
2259
+ if (intval($num) >0 || $num == '0') {
2260
+ if (!$font['isUnicode']) {
2261
+ // With Unicode, widths array isn't used
2262
+ if ($lastChar>0 && $num>$lastChar+1) {
2263
+ for ($i = $lastChar+1;$i<$num;$i++) {
2264
+ $widths[] = 0;
2265
+ }
2266
+ }
2267
+ }
2268
+
2269
+ $widths[] = $d;
2270
+
2271
+ if ($font['isUnicode']) {
2272
+ $cid_widths[$num] = $d;
2273
+ }
2274
+
2275
+ if ($firstChar == -1) {
2276
+ $firstChar = $num;
2277
+ }
2278
+
2279
+ $lastChar = $num;
2280
+ }
2281
+ }
2282
+
2283
+ // also need to adjust the widths for the differences array
2284
+ if (isset($options['differences'])) {
2285
+ foreach($options['differences'] as $charNum => $charName) {
2286
+ if ($charNum > $lastChar) {
2287
+ if (!$font['isUnicode']) {
2288
+ // With Unicode, widths array isn't used
2289
+ for ($i = $lastChar + 1; $i <= $charNum; $i++) {
2290
+ $widths[] = 0;
2291
+ }
2292
+ }
2293
+
2294
+ $lastChar = $charNum;
2295
+ }
2296
+
2297
+ if (isset($font['C'][$charName])) {
2298
+ $widths[$charNum-$firstChar] = $font['C'][$charName];
2299
+ if ($font['isUnicode']) {
2300
+ $cid_widths[$charName] = $font['C'][$charName];
2301
+ }
2302
+ }
2303
+ }
2304
+ }
2305
+
2306
+ if ($font['isUnicode']) {
2307
+ $font['CIDWidths'] = $cid_widths;
2308
+ }
2309
+
2310
+ $this->addMessage('selectFont: FirstChar = '.$firstChar);
2311
+ $this->addMessage('selectFont: LastChar = '.$lastChar);
2312
+
2313
+ $widthid = -1;
2314
+
2315
+ if (!$font['isUnicode']) {
2316
+ // With Unicode, widths array isn't used
2317
+
2318
+ $this->numObj++;
2319
+ $this->o_contents($this->numObj, 'new', 'raw');
2320
+ $this->objects[$this->numObj]['c'].= '['.implode(' ', $widths).']';
2321
+ $widthid = $this->numObj;
2322
+ }
2323
+
2324
+ $missing_width = 500;
2325
+ $stemV = 70;
2326
+
2327
+ if (isset($font['MissingWidth'])) {
2328
+ $missing_width = $font['MissingWidth'];
2329
+ }
2330
+ if (isset($font['StdVW'])) {
2331
+ $stemV = $font['StdVW'];
2332
+ } elseif (isset($font['Weight']) && preg_match('!(bold|black)!i', $font['Weight'])) {
2333
+ $stemV = 120;
2334
+ }
2335
+
2336
+ // load the pfb file, and put that into an object too.
2337
+ // note that pdf supports only binary format type 1 font files, though there is a
2338
+ // simple utility to convert them from pfa to pfb.
2339
+ if (!$this->isUnicode || $fbtype !== 'ttf' || empty($this->stringSubsets)) {
2340
+ $data = file_get_contents($fbfile);
2341
+ }
2342
+ else {
2343
+ require_once dirname(__FILE__)."/php-font-lib/classes/font.cls.php";
2344
+
2345
+ $this->stringSubsets[$fontName][] = 32; // Force space if not in yet
2346
+
2347
+ $subset = $this->stringSubsets[$fontName];
2348
+ sort($subset);
2349
+
2350
+ // Load font
2351
+ $font_obj = Font::load($fbfile);
2352
+ $font_obj->parse();
2353
+
2354
+ // Define subset
2355
+ $font_obj->setSubset($subset);
2356
+ $font_obj->reduce();
2357
+
2358
+ // Write new font
2359
+ $tmp_name = "$fbfile.tmp.".sprintf("%u", crc32(implode($subset)));
2360
+ $font_obj->open($tmp_name, Font_Binary_Stream::modeWrite);
2361
+ $font_obj->encode(array("OS/2"));
2362
+ $font_obj->close();
2363
+
2364
+ // Parse the new font to get cid2gid and widths
2365
+ $font_obj = Font::load($tmp_name);
2366
+
2367
+ // Find Unicode char map table
2368
+ $subtable = null;
2369
+ foreach($font_obj->getData("cmap", "subtables") as $_subtable) {
2370
+ if ($_subtable["platformID"] == 0 || $_subtable["platformID"] == 3 && $_subtable["platformSpecificID"] == 1) {
2371
+ $subtable = $_subtable;
2372
+ break;
2373
+ }
2374
+ }
2375
+
2376
+ if ($subtable) {
2377
+ $glyphIndexArray = $subtable["glyphIndexArray"];
2378
+ $hmtx = $font_obj->getData("hmtx");
2379
+
2380
+ unset($glyphIndexArray[0xFFFF]);
2381
+
2382
+ $cidtogid = str_pad('', max(array_keys($glyphIndexArray))*2+1, "\x00");
2383
+ $font['CIDWidths'] = array();
2384
+
2385
+ foreach($glyphIndexArray as $cid => $gid) {
2386
+ if ($cid >= 0 && $cid < 0xFFFF && $gid) {
2387
+ $cidtogid[$cid*2] = chr($gid >> 8);
2388
+ $cidtogid[$cid*2 + 1] = chr($gid & 0xFF);
2389
+ }
2390
+
2391
+ $width = $font_obj->normalizeFUnit(isset($hmtx[$gid]) ? $hmtx[$gid][0] : $hmtx[0][0]);
2392
+ $font['CIDWidths'][$cid] = $width;
2393
+ }
2394
+
2395
+ $font['CIDtoGID'] = base64_encode(gzcompress($cidtogid));
2396
+ $font['CIDtoGID_Compressed'] = true;
2397
+
2398
+ $data = file_get_contents($tmp_name);
2399
+ }
2400
+ else {
2401
+ $data = file_get_contents($fbfile);
2402
+ }
2403
+
2404
+ $font_obj->close();
2405
+ unlink($tmp_name);
2406
+ }
2407
+
2408
+ // create the font descriptor
2409
+ $this->numObj++;
2410
+ $fontDescriptorId = $this->numObj;
2411
+
2412
+ $this->numObj++;
2413
+ $pfbid = $this->numObj;
2414
+
2415
+ // determine flags (more than a little flakey, hopefully will not matter much)
2416
+ $flags = 0;
2417
+
2418
+ if ($font['ItalicAngle'] != 0) {
2419
+ $flags+= pow(2, 6);
2420
+ }
2421
+
2422
+ if ($font['IsFixedPitch'] === 'true') {
2423
+ $flags+= 1;
2424
+ }
2425
+
2426
+ $flags+= pow(2, 5); // assume non-sybolic
2427
+ $list = array(
2428
+ 'Ascent' => 'Ascender',
2429
+ 'CapHeight' => 'CapHeight',
2430
+ 'MissingWidth' => 'MissingWidth',
2431
+ 'Descent' => 'Descender',
2432
+ 'FontBBox' => 'FontBBox',
2433
+ 'ItalicAngle' => 'ItalicAngle'
2434
+ );
2435
+ $fdopt = array(
2436
+ 'Flags' => $flags,
2437
+ 'FontName' => $adobeFontName,
2438
+ 'StemV' => $stemV
2439
+ );
2440
+
2441
+ foreach($list as $k => $v) {
2442
+ if (isset($font[$v])) {
2443
+ $fdopt[$k] = $font[$v];
2444
+ }
2445
+ }
2446
+
2447
+ if ($fbtype === 'pfb') {
2448
+ $fdopt['FontFile'] = $pfbid;
2449
+ } else if ($fbtype === 'ttf') {
2450
+ $fdopt['FontFile2'] = $pfbid;
2451
+ }
2452
+
2453
+ $this->o_fontDescriptor($fontDescriptorId, 'new', $fdopt);
2454
+
2455
+ // embed the font program
2456
+ $this->o_contents($this->numObj, 'new');
2457
+ $this->objects[$pfbid]['c'].= $data;
2458
+
2459
+ // determine the cruicial lengths within this file
2460
+ if ($fbtype === 'pfb') {
2461
+ $l1 = strpos($data, 'eexec') +6;
2462
+ $l2 = strpos($data, '00000000') -$l1;
2463
+ $l3 = mb_strlen($data, '8bit') -$l2-$l1;
2464
+ $this->o_contents($this->numObj, 'add', array('Length1' => $l1, 'Length2' => $l2, 'Length3' => $l3));
2465
+ } else if ($fbtype == 'ttf') {
2466
+ $l1 = mb_strlen($data, '8bit');
2467
+ $this->o_contents($this->numObj, 'add', array('Length1' => $l1));
2468
+ }
2469
+
2470
+ // tell the font object about all this new stuff
2471
+ $tmp = array(
2472
+ 'BaseFont' => $adobeFontName,
2473
+ 'MissingWidth' => $missing_width,
2474
+ 'Widths' => $widthid,
2475
+ 'FirstChar' => $firstChar,
2476
+ 'LastChar' => $lastChar,
2477
+ 'FontDescriptor' => $fontDescriptorId,
2478
+ );
2479
+
2480
+ if ($fbtype === 'ttf') {
2481
+ $tmp['SubType'] = 'TrueType';
2482
+ }
2483
+
2484
+ $this->addMessage("adding extra info to font.($fontObj)");
2485
+
2486
+ foreach($tmp as $fk => $fv) {
2487
+ $this->addMessage("$fk : $fv");
2488
+ }
2489
+
2490
+ $this->o_font($fontObj, 'add', $tmp);
2491
+ } else {
2492
+ $this->addMessage('selectFont: pfb or ttf file not found, ok if this is one of the 14 standard fonts');
2493
+ }
2494
+
2495
+ // also set the differences here, note that this means that these will take effect only the
2496
+ //first time that a font is selected, else they are ignored
2497
+ if (isset($options['differences'])) {
2498
+ $font['differences'] = $options['differences'];
2499
+ }
2500
+ }
2501
+ }
2502
+
2503
+ if ($set && isset($this->fonts[$fontName])) {
2504
+ // so if for some reason the font was not set in the last one then it will not be selected
2505
+ $this->currentBaseFont = $fontName;
2506
+
2507
+ // the next lines mean that if a new font is selected, then the current text state will be
2508
+ // applied to it as well.
2509
+ $this->currentFont = $this->currentBaseFont;
2510
+ $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
2511
+
2512
+ //$this->setCurrentFont();
2513
+ }
2514
+
2515
+ return $this->currentFontNum;
2516
+ //return $this->numObj;
2517
+ }
2518
+
2519
+ /**
2520
+ * sets up the current font, based on the font families, and the current text state
2521
+ * note that this system is quite flexible, a bold-italic font can be completely different to a
2522
+ * italic-bold font, and even bold-bold will have to be defined within the family to have meaning
2523
+ * This function is to be called whenever the currentTextState is changed, it will update
2524
+ * the currentFont setting to whatever the appropriatte family one is.
2525
+ * If the user calls selectFont themselves then that will reset the currentBaseFont, and the currentFont
2526
+ * This function will change the currentFont to whatever it should be, but will not change the
2527
+ * currentBaseFont.
2528
+ *
2529
+ * @access private
2530
+ */
2531
+ function setCurrentFont() {
2532
+ // if (strlen($this->currentBaseFont) == 0){
2533
+ // // then assume an initial font
2534
+ // $this->selectFont($this->defaultFont);
2535
+ // }
2536
+ // $cf = substr($this->currentBaseFont,strrpos($this->currentBaseFont,'/')+1);
2537
+ // if (strlen($this->currentTextState)
2538
+ // && isset($this->fontFamilies[$cf])
2539
+ // && isset($this->fontFamilies[$cf][$this->currentTextState])){
2540
+ // // then we are in some state or another
2541
+ // // and this font has a family, and the current setting exists within it
2542
+ // // select the font, then return it
2543
+ // $nf = substr($this->currentBaseFont,0,strrpos($this->currentBaseFont,'/')+1).$this->fontFamilies[$cf][$this->currentTextState];
2544
+ // $this->selectFont($nf,'',0);
2545
+ // $this->currentFont = $nf;
2546
+ // $this->currentFontNum = $this->fonts[$nf]['fontNum'];
2547
+ // } else {
2548
+ // // the this font must not have the right family member for the current state
2549
+ // // simply assume the base font
2550
+ $this->currentFont = $this->currentBaseFont;
2551
+ $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
2552
+ // }
2553
+ }
2554
+
2555
+ /**
2556
+ * function for the user to find out what the ID is of the first page that was created during
2557
+ * startup - useful if they wish to add something to it later.
2558
+ */
2559
+ function getFirstPageId() {
2560
+ return $this->firstPageId;
2561
+ }
2562
+
2563
+ /**
2564
+ * add content to the currently active object
2565
+ *
2566
+ * @access private
2567
+ */
2568
+ function addContent($content) {
2569
+ $this->objects[$this->currentContents]['c'].= $content;
2570
+ }
2571
+
2572
+ /**
2573
+ * sets the colour for fill operations
2574
+ */
2575
+ function setColor($color, $force = false) {
2576
+ $new_color = array($color[0], $color[1], $color[2], isset($color[3]) ? $color[3] : null);
2577
+
2578
+ if (!$force && $this->currentColour == $new_color) return;
2579
+
2580
+ if (isset($new_color[3])) {
2581
+ $this->currentColour = $new_color;
2582
+ $this->objects[$this->currentContents]['c'] .= vsprintf("\n%.3F %.3F %.3F %.3F k", $this->currentColour);
2583
+ }
2584
+
2585
+ elseif (isset($new_color[2])) {
2586
+ $this->currentColour = $new_color;
2587
+ $this->objects[$this->currentContents]['c'] .= vsprintf("\n%.3F %.3F %.3F rg", $this->currentColour);
2588
+ }
2589
+ }
2590
+
2591
+ /**
2592
+ * sets the colour for stroke operations
2593
+ */
2594
+ function setStrokeColor($color, $force = false) {
2595
+ $new_color = array($color[0], $color[1], $color[2], isset($color[3]) ? $color[3] : null);
2596
+
2597
+ if (!$force && $this->currentStrokeColour == $new_color) return;
2598
+
2599
+ if (isset($new_color[3])) {
2600
+ $this->currentStrokeColour = $new_color;
2601
+ $this->objects[$this->currentContents]['c'] .= vsprintf("\n%.3F %.3F %.3F %.3F K", $this->currentStrokeColour);
2602
+ }
2603
+
2604
+ elseif (isset($new_color[2])) {
2605
+ $this->currentStrokeColour = $new_color;
2606
+ $this->objects[$this->currentContents]['c'] .= vsprintf("\n%.3F %.3F %.3F RG", $this->currentStrokeColour);
2607
+ }
2608
+ }
2609
+
2610
+ /**
2611
+ * Set the graphics state for compositions
2612
+ */
2613
+ function setGraphicsState($parameters) {
2614
+ // Create a new graphics state object
2615
+ // FIXME: should actually keep track of states that have already been created...
2616
+ $this->numObj++;
2617
+ $this->o_extGState($this->numObj, 'new', $parameters);
2618
+ $this->objects[ $this->currentContents ]['c'].= "\n/GS$this->numStates gs";
2619
+ }
2620
+
2621
+ /**
2622
+ * Set current blend mode & opacity for lines.
2623
+ *
2624
+ * Valid blend modes are:
2625
+ *
2626
+ * Normal, Multiply, Screen, Overlay, Darken, Lighten,
2627
+ * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
2628
+ * Exclusion
2629
+ *
2630
+ * @param string $mode the blend mode to use
2631
+ * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
2632
+ */
2633
+ function setLineTransparency($mode, $opacity) {
2634
+ static $blend_modes = array("Normal", "Multiply", "Screen",
2635
+ "Overlay", "Darken", "Lighten",
2636
+ "ColorDogde", "ColorBurn", "HardLight",
2637
+ "SoftLight", "Difference", "Exclusion");
2638
+
2639
+ if ( !in_array($mode, $blend_modes) )
2640
+ $mode = "Normal";
2641
+
2642
+ // Only create a new graphics state if required
2643
+ if ( $mode === $this->currentLineTransparency["mode"] &&
2644
+ $opacity == $this->currentLineTransparency["opacity"] )
2645
+ return;
2646
+
2647
+ $this->currentLineTransparency["mode"] = $mode;
2648
+ $this->currentLineTransparency["opacity"] = $opacity;
2649
+
2650
+ $options = array("BM" => "/$mode",
2651
+ "CA" => (float)$opacity);
2652
+
2653
+ $this->setGraphicsState($options);
2654
+ }
2655
+
2656
+ /**
2657
+ * Set current blend mode & opacity for filled objects.
2658
+ *
2659
+ * Valid blend modes are:
2660
+ *
2661
+ * Normal, Multiply, Screen, Overlay, Darken, Lighten,
2662
+ * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
2663
+ * Exclusion
2664
+ *
2665
+ * @param string $mode the blend mode to use
2666
+ * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
2667
+ */
2668
+ function setFillTransparency($mode, $opacity) {
2669
+ static $blend_modes = array("Normal", "Multiply", "Screen",
2670
+ "Overlay", "Darken", "Lighten",
2671
+ "ColorDogde", "ColorBurn", "HardLight",
2672
+ "SoftLight", "Difference", "Exclusion");
2673
+
2674
+ if ( !in_array($mode, $blend_modes) )
2675
+ $mode = "Normal";
2676
+
2677
+ if ( $mode === $this->currentFillTransparency["mode"] &&
2678
+ $opacity == $this->currentFillTransparency["opacity"] )
2679
+ return;
2680
+
2681
+ $this->currentFillTransparency["mode"] = $mode;
2682
+ $this->currentFillTransparency["opacity"] = $opacity;
2683
+
2684
+ $options = array("BM" => "/$mode",
2685
+ "ca" => (float)$opacity);
2686
+
2687
+ $this->setGraphicsState($options);
2688
+ }
2689
+
2690
+ /**
2691
+ * draw a line from one set of coordinates to another
2692
+ */
2693
+ function line($x1, $y1, $x2, $y2) {
2694
+ $this->objects[$this->currentContents]['c'] .= sprintf("\n%.3F %.3F m %.3F %.3F l S", $x1, $y1, $x2, $y2);
2695
+ }
2696
+
2697
+ /**
2698
+ * draw a bezier curve based on 4 control points
2699
+ */
2700
+ function curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3) {
2701
+ // in the current line style, draw a bezier curve from (x0,y0) to (x3,y3) using the other two points
2702
+ // as the control points for the curve.
2703
+ $this->objects[$this->currentContents]['c'] .=
2704
+ sprintf("\n%.3F %.3F m %.3F %.3F %.3F %.3F %.3F %.3F c S", $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3);
2705
+ }
2706
+
2707
+ /**
2708
+ * draw a part of an ellipse
2709
+ */
2710
+ function partEllipse($x0, $y0, $astart, $afinish, $r1, $r2 = 0, $angle = 0, $nSeg = 8) {
2711
+ $this->ellipse($x0, $y0, $r1, $r2, $angle, $nSeg, $astart, $afinish, false);
2712
+ }
2713
+
2714
+ /**
2715
+ * draw a filled ellipse
2716
+ */
2717
+ function filledEllipse($x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360) {
2718
+ return $this->ellipse($x0, $y0, $r1, $r2 = 0, $angle, $nSeg, $astart, $afinish, true, true);
2719
+ }
2720
+
2721
+ /**
2722
+ * draw an ellipse
2723
+ * note that the part and filled ellipse are just special cases of this function
2724
+ *
2725
+ * draws an ellipse in the current line style
2726
+ * centered at $x0,$y0, radii $r1,$r2
2727
+ * if $r2 is not set, then a circle is drawn
2728
+ * nSeg is not allowed to be less than 2, as this will simply draw a line (and will even draw a
2729
+ * pretty crappy shape at 2, as we are approximating with bezier curves.
2730
+ */
2731
+ function ellipse($x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360, $close = true, $fill = false) {
2732
+ if ($r1 == 0) {
2733
+ return;
2734
+ }
2735
+
2736
+ if ($r2 == 0) {
2737
+ $r2 = $r1;
2738
+ }
2739
+
2740
+ if ($nSeg < 2) {
2741
+ $nSeg = 2;
2742
+ }
2743
+
2744
+ $astart = deg2rad((float)$astart);
2745
+ $afinish = deg2rad((float)$afinish);
2746
+ $totalAngle = $afinish-$astart;
2747
+
2748
+ $dt = $totalAngle/$nSeg;
2749
+ $dtm = $dt/3;
2750
+
2751
+ if ($angle != 0) {
2752
+ $a = -1*deg2rad((float)$angle);
2753
+
2754
+ $this->objects[$this->currentContents]['c'] .=
2755
+ sprintf("\n q %.3F %.3F %.3F %.3F %.3F %.3F cm", cos($a), -sin($a), sin($a), cos($a), $x0, $y0);
2756
+
2757
+ $x0 = 0;
2758
+ $y0 = 0;
2759
+ }
2760
+
2761
+ $t1 = $astart;
2762
+ $a0 = $x0 + $r1*cos($t1);
2763
+ $b0 = $y0 + $r2*sin($t1);
2764
+ $c0 = -$r1 * sin($t1);
2765
+ $d0 = $r2 * cos($t1);
2766
+
2767
+ $this->objects[$this->currentContents]['c'] .= sprintf("\n%.3F %.3F m ", $a0, $b0);
2768
+
2769
+ for ($i = 1; $i <= $nSeg; $i++) {
2770
+ // draw this bit of the total curve
2771
+ $t1 = $i * $dt + $astart;
2772
+ $a1 = $x0 + $r1 * cos($t1);
2773
+ $b1 = $y0 + $r2 * sin($t1);
2774
+ $c1 = -$r1 * sin($t1);
2775
+ $d1 = $r2 * cos($t1);
2776
+
2777
+ $this->objects[$this->currentContents]['c'] .=
2778
+ sprintf("\n%.3F %.3F %.3F %.3F %.3F %.3F c", ($a0+$c0*$dtm), ($b0+$d0*$dtm), ($a1-$c1*$dtm), ($b1-$d1*$dtm), $a1, $b1);
2779
+
2780
+ $a0 = $a1;
2781
+ $b0 = $b1;
2782
+ $c0 = $c1;
2783
+ $d0 = $d1;
2784
+ }
2785
+
2786
+ if ($fill) {
2787
+ $this->objects[$this->currentContents]['c'].= ' f';
2788
+ } else if ($close) {
2789
+ $this->objects[$this->currentContents]['c'].= ' s'; // small 's' signifies closing the path as well
2790
+ } else {
2791
+ $this->objects[$this->currentContents]['c'].= ' S';
2792
+ }
2793
+
2794
+ if ($angle != 0) {
2795
+ $this->objects[$this->currentContents]['c'].= ' Q';
2796
+ }
2797
+ }
2798
+
2799
+ /**
2800
+ * this sets the line drawing style.
2801
+ * width, is the thickness of the line in user units
2802
+ * cap is the type of cap to put on the line, values can be 'butt','round','square'
2803
+ * where the diffference between 'square' and 'butt' is that 'square' projects a flat end past the
2804
+ * end of the line.
2805
+ * join can be 'miter', 'round', 'bevel'
2806
+ * dash is an array which sets the dash pattern, is a series of length values, which are the lengths of the
2807
+ * on and off dashes.
2808
+ * (2) represents 2 on, 2 off, 2 on , 2 off ...
2809
+ * (2,1) is 2 on, 1 off, 2 on, 1 off.. etc
2810
+ * phase is a modifier on the dash pattern which is used to shift the point at which the pattern starts.
2811
+ */
2812
+ function setLineStyle($width = 1, $cap = '', $join = '', $dash = '', $phase = 0) {
2813
+ // this is quite inefficient in that it sets all the parameters whenever 1 is changed, but will fix another day
2814
+ $string = '';
2815
+
2816
+ if ($width>0) {
2817
+ $string.= "$width w";
2818
+ }
2819
+
2820
+ $ca = array('butt' => 0, 'round' => 1, 'square' => 2);
2821
+
2822
+ if (isset($ca[$cap])) {
2823
+ $string.= " $ca[$cap] J";
2824
+ }
2825
+
2826
+ $ja = array('miter' => 0, 'round' => 1, 'bevel' => 2);
2827
+
2828
+ if (isset($ja[$join])) {
2829
+ $string.= " $ja[$join] j";
2830
+ }
2831
+
2832
+ if (is_array($dash)) {
2833
+ $string.= ' [ ' . implode(' ', $dash) . " ] $phase d";
2834
+ }
2835
+
2836
+ $this->currentLineStyle = $string;
2837
+ $this->objects[$this->currentContents]['c'].= "\n$string";
2838
+ }
2839
+
2840
+ /**
2841
+ * draw a polygon, the syntax for this is similar to the GD polygon command
2842
+ */
2843
+ function polygon($p, $np, $f = false) {
2844
+ $this->objects[$this->currentContents]['c'].= sprintf("\n%.3F %.3F m ", $p[0], $p[1]);
2845
+
2846
+ for ($i = 2; $i < $np * 2; $i = $i + 2) {
2847
+ $this->objects[$this->currentContents]['c'].= sprintf("%.3F %.3F l ", $p[$i], $p[$i+1]);
2848
+ }
2849
+
2850
+ if ($f) {
2851
+ $this->objects[$this->currentContents]['c'].= ' f';
2852
+ } else {
2853
+ $this->objects[$this->currentContents]['c'].= ' S';
2854
+ }
2855
+ }
2856
+
2857
+ /**
2858
+ * a filled rectangle, note that it is the width and height of the rectangle which are the secondary paramaters, not
2859
+ * the coordinates of the upper-right corner
2860
+ */
2861
+ function filledRectangle($x1, $y1, $width, $height) {
2862
+ $this->objects[$this->currentContents]['c'].= sprintf("\n%.3F %.3F %.3F %.3F re f", $x1, $y1, $width, $height);
2863
+ }
2864
+
2865
+ /**
2866
+ * draw a rectangle, note that it is the width and height of the rectangle which are the secondary paramaters, not
2867
+ * the coordinates of the upper-right corner
2868
+ */
2869
+ function rectangle($x1, $y1, $width, $height) {
2870
+ $this->objects[$this->currentContents]['c'].= sprintf("\n%.3F %.3F %.3F %.3F re S", $x1, $y1, $width, $height);
2871
+ }
2872
+
2873
+ /**
2874
+ * save the current graphic state
2875
+ */
2876
+ function save() {
2877
+ // we must reset the colour cache or it will keep bad colours after clipping
2878
+ $this->currentColour = null;
2879
+ $this->currentStrokeColour = null;
2880
+ $this->objects[$this->currentContents]['c'].= "\nq";
2881
+ }
2882
+
2883
+ /**
2884
+ * restore the last graphic state
2885
+ */
2886
+ function restore() {
2887
+ $this->objects[$this->currentContents]['c'].= "\nQ";
2888
+ }
2889
+
2890
+ /**
2891
+ * draw a clipping rectangle, all the elements added after this will be clipped
2892
+ */
2893
+ function clippingRectangle($x1, $y1, $width, $height) {
2894
+ $this->save();
2895
+ $this->objects[$this->currentContents]['c'].= sprintf("\n%.3F %.3F %.3F %.3F re W n", $x1, $y1, $width, $height);
2896
+ }
2897
+
2898
+ /**
2899
+ * ends the last clipping shape
2900
+ */
2901
+ function clippingEnd() {
2902
+ $this->restore();
2903
+ }
2904
+
2905
+ /**
2906
+ * scale
2907
+ * @param float $s_x scaling factor for width as percent
2908
+ * @param float $s_y scaling factor for height as percent
2909
+ * @param float $x Origin abscisse
2910
+ * @param float $y Origin ordinate
2911
+ */
2912
+ function scale($s_x, $s_y, $x, $y) {
2913
+ $y = $this->currentPageSize["height"] - $y;
2914
+
2915
+ $tm = array(
2916
+ $s_x, 0,
2917
+ 0, $s_y,
2918
+ $x*(1-$s_x), $y*(1-$s_y)
2919
+ );
2920
+
2921
+ $this->transform($tm);
2922
+ }
2923
+
2924
+ /**
2925
+ * translate
2926
+ * @param float $t_x movement to the right
2927
+ * @param float $t_y movement to the bottom
2928
+ */
2929
+ function translate($t_x, $t_y) {
2930
+ $tm = array(
2931
+ 1, 0,
2932
+ 0, 1,
2933
+ $t_x, -$t_y
2934
+ );
2935
+
2936
+ $this->transform($tm);
2937
+ }
2938
+
2939
+ /**
2940
+ * rotate
2941
+ * @param float $angle angle in degrees for counter-clockwise rotation
2942
+ * @param float $x Origin abscisse
2943
+ * @param float $y Origin ordinate
2944
+ */
2945
+ function rotate($angle, $x, $y) {
2946
+ $y = $this->currentPageSize["height"] - $y;
2947
+
2948
+ $a = deg2rad($angle);
2949
+ $cos_a = cos($a);
2950
+ $sin_a = sin($a);
2951
+
2952
+ $tm = array(
2953
+ $cos_a, -$sin_a,
2954
+ $sin_a, $cos_a,
2955
+ $x - $sin_a*$y - $cos_a*$x, $y - $cos_a*$y + $sin_a*$x,
2956
+ );
2957
+
2958
+ $this->transform($tm);
2959
+ }
2960
+
2961
+ /**
2962
+ * skew
2963
+ * @param float $angle_x
2964
+ * @param float $angle_y
2965
+ * @param float $x Origin abscisse
2966
+ * @param float $y Origin ordinate
2967
+ */
2968
+ function skew($angle_x, $angle_y, $x, $y) {
2969
+ $y = $this->currentPageSize["height"] - $y;
2970
+
2971
+ $tan_x = tan(deg2rad($angle_x));
2972
+ $tan_y = tan(deg2rad($angle_y));
2973
+
2974
+ $tm = array(
2975
+ 1, -$tan_y,
2976
+ -$tan_x, 1,
2977
+ $tan_x*$y, $tan_y*$x,
2978
+ );
2979
+
2980
+ $this->transform($tm);
2981
+ }
2982
+
2983
+ /**
2984
+ * apply graphic transformations
2985
+ * @param array $tm transformation matrix
2986
+ */
2987
+ function transform($tm) {
2988
+ $this->objects[$this->currentContents]['c'].=
2989
+ vsprintf("\n %.3F %.3F %.3F %.3F %.3F %.3F cm", $tm);
2990
+ }
2991
+
2992
+ /**
2993
+ * add a new page to the document
2994
+ * this also makes the new page the current active object
2995
+ */
2996
+ function newPage($insert = 0, $id = 0, $pos = 'after') {
2997
+ // if there is a state saved, then go up the stack closing them
2998
+ // then on the new page, re-open them with the right setings
2999
+
3000
+ if ($this->nStateStack) {
3001
+ for ($i = $this->nStateStack;$i >= 1;$i--) {
3002
+ $this->restoreState($i);
3003
+ }
3004
+ }
3005
+
3006
+ $this->numObj++;
3007
+
3008
+ if ($insert) {
3009
+ // the id from the ezPdf class is the id of the contents of the page, not the page object itself
3010
+ // query that object to find the parent
3011
+ $rid = $this->objects[$id]['onPage'];
3012
+ $opt = array('rid' => $rid, 'pos' => $pos);
3013
+ $this->o_page($this->numObj, 'new', $opt);
3014
+ } else {
3015
+ $this->o_page($this->numObj, 'new');
3016
+ }
3017
+
3018
+ // if there is a stack saved, then put that onto the page
3019
+ if ($this->nStateStack) {
3020
+ for ($i = 1;$i <= $this->nStateStack;$i++) {
3021
+ $this->saveState($i);
3022
+ }
3023
+ }
3024
+
3025
+ // and if there has been a stroke or fill colour set, then transfer them
3026
+ if (isset($this->currentColour)) {
3027
+ $this->setColor($this->currentColour, true);
3028
+ }
3029
+
3030
+ if (isset($this->currentStrokeColour)) {
3031
+ $this->setStrokeColor($this->currentStrokeColour, true);
3032
+ }
3033
+
3034
+ // if there is a line style set, then put this in too
3035
+ if (mb_strlen($this->currentLineStyle, '8bit')) {
3036
+ $this->objects[$this->currentContents]['c'].= "\n$this->currentLineStyle";
3037
+ }
3038
+
3039
+ // the call to the o_page object set currentContents to the present page, so this can be returned as the page id
3040
+ return $this->currentContents;
3041
+ }
3042
+
3043
+ /**
3044
+ * output the pdf code, streaming it to the browser
3045
+ * the relevant headers are set so that hopefully the browser will recognise it
3046
+ */
3047
+ function stream($options = '') {
3048
+ // setting the options allows the adjustment of the headers
3049
+ // values at the moment are:
3050
+ // 'Content-Disposition' => 'filename' - sets the filename, though not too sure how well this will
3051
+ // work as in my trial the browser seems to use the filename of the php file with .pdf on the end
3052
+ // 'Accept-Ranges' => 1 or 0 - if this is not set to 1, then this header is not included, off by default
3053
+ // this header seems to have caused some problems despite tha fact that it is supposed to solve
3054
+ // them, so I am leaving it off by default.
3055
+ // 'compress' = > 1 or 0 - apply content stream compression, this is on (1) by default
3056
+ // 'Attachment' => 1 or 0 - if 1, force the browser to open a download dialog
3057
+ if (!is_array($options)) {
3058
+ $options = array();
3059
+ }
3060
+
3061
+ if ( headers_sent())
3062
+ die("Unable to stream pdf: headers already sent");
3063
+
3064
+ $debug = empty($options['compression']);
3065
+ $tmp = ltrim($this->output($debug));
3066
+
3067
+ header("Cache-Control: private");
3068
+ header("Content-type: application/pdf");
3069
+
3070
+ //FIXME: I don't know that this is sufficient for determining content length (i.e. what about transport compression?)
3071
+ header("Content-Length: " . mb_strlen($tmp, '8bit'));
3072
+ $fileName = (isset($options['Content-Disposition']) ? $options['Content-Disposition'] : 'file.pdf');
3073
+
3074
+ if ( !isset($options["Attachment"]))
3075
+ $options["Attachment"] = true;
3076
+
3077
+ $attachment = $options["Attachment"] ? "attachment" : "inline";
3078
+
3079
+ header("Content-Disposition: $attachment; filename=\"$fileName\"");
3080
+
3081
+ if (isset($options['Accept-Ranges']) && $options['Accept-Ranges'] == 1) {
3082
+ //FIXME: Is this the correct value ... spec says 1#range-unit
3083
+ header("Accept-Ranges: " . mb_strlen($tmp, '8bit'));
3084
+ }
3085
+
3086
+ echo $tmp;
3087
+ flush();
3088
+ }
3089
+
3090
+ /**
3091
+ * return the height in units of the current font in the given size
3092
+ */
3093
+ function getFontHeight($size) {
3094
+ if (!$this->numFonts) {
3095
+ $this->selectFont($this->defaultFont);
3096
+ }
3097
+
3098
+ $font = $this->fonts[$this->currentFont];
3099
+
3100
+ // for the current font, and the given size, what is the height of the font in user units
3101
+ if ( isset($font['Ascender']) && isset($font['Descender']) ) {
3102
+ $h = $font['Ascender']-$font['Descender'];
3103
+ }
3104
+ else {
3105
+ $h = $font['FontBBox'][3]-$font['FontBBox'][1];
3106
+ }
3107
+
3108
+ // have to adjust by a font offset for Windows fonts. unfortunately it looks like
3109
+ // the bounding box calculations are wrong and I don't know why.
3110
+ if (isset($font['FontHeightOffset'])) {
3111
+ // For CourierNew from Windows this needs to be -646 to match the
3112
+ // Adobe native Courier font.
3113
+ //
3114
+ // For FreeMono from GNU this needs to be -337 to match the
3115
+ // Courier font.
3116
+ //
3117
+ // Both have been added manually to the .afm and .ufm files.
3118
+ $h += (int)$font['FontHeightOffset'];
3119
+ }
3120
+
3121
+ return $size*$h/1000;
3122
+ }
3123
+
3124
+ function getFontXHeight($size) {
3125
+ if (!$this->numFonts) {
3126
+ $this->selectFont($this->defaultFont);
3127
+ }
3128
+
3129
+ $font = $this->fonts[$this->currentFont];
3130
+
3131
+ // for the current font, and the given size, what is the height of the font in user units
3132
+ if ( isset($font['XHeight']) ) {
3133
+ $xh = $font['Ascender']-$font['Descender'];
3134
+ }
3135
+ else {
3136
+ $xh = $this->getFontHeight($size) / 2;
3137
+ }
3138
+
3139
+ return $size*$xh/1000;
3140
+ }
3141
+
3142
+ /**
3143
+ * return the font descender, this will normally return a negative number
3144
+ * if you add this number to the baseline, you get the level of the bottom of the font
3145
+ * it is in the pdf user units
3146
+ */
3147
+ function getFontDescender($size) {
3148
+ // note that this will most likely return a negative value
3149
+ if (!$this->numFonts) {
3150
+ $this->selectFont($this->defaultFont);
3151
+ }
3152
+
3153
+ //$h = $this->fonts[$this->currentFont]['FontBBox'][1];
3154
+ $h = $this->fonts[$this->currentFont]['Descender'];
3155
+
3156
+ return $size*$h/1000;
3157
+ }
3158
+
3159
+ /**
3160
+ * filter the text, this is applied to all text just before being inserted into the pdf document
3161
+ * it escapes the various things that need to be escaped, and so on
3162
+ *
3163
+ * @access private
3164
+ */
3165
+ function filterText($text, $bom = true, $convert_encoding = true) {
3166
+ if (!$this->numFonts) {
3167
+ $this->selectFont($this->defaultFont);
3168
+ }
3169
+
3170
+ if ($convert_encoding) {
3171
+ $cf = $this->currentFont;
3172
+ if (isset($this->fonts[$cf]) && $this->fonts[$cf]['isUnicode']) {
3173
+ //$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
3174
+ $text = $this->utf8toUtf16BE($text, $bom);
3175
+ } else {
3176
+ //$text = html_entity_decode($text, ENT_QUOTES);
3177
+ $text = mb_convert_encoding($text, self::$targetEncoding, 'UTF-8');
3178
+ }
3179
+ }
3180
+
3181
+ // the chr(13) substitution fixes a bug seen in TCPDF (bug #1421290)
3182
+ return strtr($text, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
3183
+ }
3184
+
3185
+ /**
3186
+ * return array containing codepoints (UTF-8 character values) for the
3187
+ * string passed in.
3188
+ *
3189
+ * based on the excellent TCPDF code by Nicola Asuni and the
3190
+ * RFC for UTF-8 at http://www.faqs.org/rfcs/rfc3629.html
3191
+ *
3192
+ * @access private
3193
+ * @author Orion Richardson
3194
+ * @since January 5, 2008
3195
+ * @param string $text UTF-8 string to process
3196
+ * @return array UTF-8 codepoints array for the string
3197
+ */
3198
+ function utf8toCodePointsArray(&$text) {
3199
+ $length = mb_strlen($text, '8bit'); // http://www.php.net/manual/en/function.mb-strlen.php#77040
3200
+ $unicode = array(); // array containing unicode values
3201
+ $bytes = array(); // array containing single character byte sequences
3202
+ $numbytes = 1; // number of octetc needed to represent the UTF-8 character
3203
+
3204
+ for ($i = 0; $i < $length; $i++) {
3205
+ $c = ord($text[$i]); // get one string character at time
3206
+ if (count($bytes) === 0) { // get starting octect
3207
+ if ($c <= 0x7F) {
3208
+ $unicode[] = $c; // use the character "as is" because is ASCII
3209
+ $numbytes = 1;
3210
+ } elseif (($c >> 0x05) === 0x06) { // 2 bytes character (0x06 = 110 BIN)
3211
+ $bytes[] = ($c - 0xC0) << 0x06;
3212
+ $numbytes = 2;
3213
+ } elseif (($c >> 0x04) === 0x0E) { // 3 bytes character (0x0E = 1110 BIN)
3214
+ $bytes[] = ($c - 0xE0) << 0x0C;
3215
+ $numbytes = 3;
3216
+ } elseif (($c >> 0x03) === 0x1E) { // 4 bytes character (0x1E = 11110 BIN)
3217
+ $bytes[] = ($c - 0xF0) << 0x12;
3218
+ $numbytes = 4;
3219
+ } else {
3220
+ // use replacement character for other invalid sequences
3221
+ $unicode[] = 0xFFFD;
3222
+ $bytes = array();
3223
+ $numbytes = 1;
3224
+ }
3225
+ } elseif (($c >> 0x06) === 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN
3226
+ $bytes[] = $c - 0x80;
3227
+ if (count($bytes) === $numbytes) {
3228
+ // compose UTF-8 bytes to a single unicode value
3229
+ $c = $bytes[0];
3230
+ for ($j = 1; $j < $numbytes; $j++) {
3231
+ $c += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
3232
+ }
3233
+ if ((($c >= 0xD800) AND ($c <= 0xDFFF)) OR ($c >= 0x10FFFF)) {
3234
+ // The definition of UTF-8 prohibits encoding character numbers between
3235
+ // U+D800 and U+DFFF, which are reserved for use with the UTF-16
3236
+ // encoding form (as surrogate pairs) and do not directly represent
3237
+ // characters.
3238
+ $unicode[] = 0xFFFD; // use replacement character
3239
+ } else {
3240
+ $unicode[] = $c; // add char to array
3241
+ }
3242
+ // reset data for next char
3243
+ $bytes = array();
3244
+ $numbytes = 1;
3245
+ }
3246
+ } else {
3247
+ // use replacement character for other invalid sequences
3248
+ $unicode[] = 0xFFFD;
3249
+ $bytes = array();
3250
+ $numbytes = 1;
3251
+ }
3252
+ }
3253
+ return $unicode;
3254
+ }
3255
+
3256
+ /**
3257
+ * convert UTF-8 to UTF-16 with an additional byte order marker
3258
+ * at the front if required.
3259
+ *
3260
+ * based on the excellent TCPDF code by Nicola Asuni and the
3261
+ * RFC for UTF-8 at http://www.faqs.org/rfcs/rfc3629.html
3262
+ *
3263
+ * @access private
3264
+ * @author Orion Richardson
3265
+ * @since January 5, 2008
3266
+ * @param string $text UTF-8 string to process
3267
+ * @param boolean $bom whether to add the byte order marker
3268
+ * @return string UTF-16 result string
3269
+ */
3270
+ function utf8toUtf16BE(&$text, $bom = true) {
3271
+ $cf = $this->currentFont;
3272
+ if (!$this->fonts[$cf]['isUnicode']) return $text;
3273
+ $out = $bom ? "\xFE\xFF" : '';
3274
+
3275
+ $unicode = $this->utf8toCodePointsArray($text);
3276
+ foreach ($unicode as $c) {
3277
+ if ($c === 0xFFFD) {
3278
+ $out .= "\xFF\xFD"; // replacement character
3279
+ } elseif ($c < 0x10000) {
3280
+ $out .= chr($c >> 0x08) . chr($c & 0xFF);
3281
+ } else {
3282
+ $c -= 0x10000;
3283
+ $w1 = 0xD800 | ($c >> 0x10);
3284
+ $w2 = 0xDC00 | ($c & 0x3FF);
3285
+ $out .= chr($w1 >> 0x08) . chr($w1 & 0xFF) . chr($w2 >> 0x08) . chr($w2 & 0xFF);
3286
+ }
3287
+ }
3288
+ return $out;
3289
+ }
3290
+
3291
+ /**
3292
+ * given a start position and information about how text is to be laid out, calculate where
3293
+ * on the page the text will end
3294
+ *
3295
+ * @access private
3296
+ */
3297
+ function PRVTgetTextPosition($x, $y, $angle, $size, $wa, $text) {
3298
+ // given this information return an array containing x and y for the end position as elements 0 and 1
3299
+ $w = $this->getTextWidth($size, $text);
3300
+
3301
+ // need to adjust for the number of spaces in this text
3302
+ $words = explode(' ', $text);
3303
+ $nspaces = count($words) -1;
3304
+ $w+= $wa*$nspaces;
3305
+ $a = deg2rad((float)$angle);
3306
+
3307
+ return array(cos($a) *$w+$x, -sin($a) *$w+$y);
3308
+ }
3309
+
3310
+ /**
3311
+ * wrapper function for PRVTcheckTextDirective1
3312
+ *
3313
+ * @access private
3314
+ */
3315
+ function PRVTcheckTextDirective(&$text, $i, &$f) {
3316
+ return 0;
3317
+ $x = 0;
3318
+ $y = 0;
3319
+ return $this->PRVTcheckTextDirective1($text, $i, $f, 0, $x, $y);
3320
+ }
3321
+
3322
+ /**
3323
+ * checks if the text stream contains a control directive
3324
+ * if so then makes some changes and returns the number of characters involved in the directive
3325
+ * this has been re-worked to include everything neccesary to find the current writing point, so that
3326
+ * the location can be sent to the callback function if required
3327
+ * if the directive does not require a font change, then $f should be set to 0
3328
+ *
3329
+ * @access private
3330
+ */
3331
+ function PRVTcheckTextDirective1(&$text, $i, &$f, $final, &$x, &$y, $size = 0, $angle = 0, $wordSpaceAdjust = 0) {
3332
+ return 0;
3333
+ $directive = 0;
3334
+ $j = $i;
3335
+ if ($text[$j] === '<') {
3336
+ $j++;
3337
+ switch ($text[$j]) {
3338
+ case '/':
3339
+ $j++;
3340
+ if (mb_strlen($text) <= $j) {
3341
+ return $directive;
3342
+ }
3343
+
3344
+ switch ($text[$j]) {
3345
+ case 'b':
3346
+ case 'i':
3347
+ $j++;
3348
+ if ($text[$j] === '>') {
3349
+ $p = mb_strrpos($this->currentTextState, $text[$j-1]);
3350
+
3351
+ if ($p !== false) {
3352
+ // then there is one to remove
3353
+ $this->currentTextState = mb_substr($this->currentTextState, 0, $p) .substr($this->currentTextState, $p+1);
3354
+ }
3355
+
3356
+ $directive = $j-$i+1;
3357
+ }
3358
+ break;
3359
+
3360
+ case 'c':
3361
+ // this this might be a callback function
3362
+ $j++;
3363
+ $k = mb_strpos($text, '>', $j);
3364
+
3365
+ if ($k !== false && $text[$j] === ':') {
3366
+ // then this will be treated as a callback directive
3367
+ $directive = $k-$i+1;
3368
+ $f = 0;
3369
+ // split the remainder on colons to get the function name and the paramater
3370
+ $tmp = mb_substr($text, $j+1, $k-$j-1);
3371
+ $b1 = mb_strpos($tmp, ':');
3372
+
3373
+ if ($b1 !== false) {
3374
+ $func = mb_substr($tmp, 0, $b1);
3375
+ $parm = mb_substr($tmp, $b1+1);
3376
+ } else {
3377
+ $func = $tmp;
3378
+ $parm = '';
3379
+ }
3380
+
3381
+ if (!isset($func) || !mb_strlen(trim($func), '8bit')) {
3382
+ $directive = 0;
3383
+ } else {
3384
+ // only call the function if this is the final call
3385
+ if ($final) {
3386
+ // need to assess the text position, calculate the text width to this point
3387
+ // can use getTextWidth to find the text width I think
3388
+ $tmp = $this->PRVTgetTextPosition($x, $y, $angle, $size, $wordSpaceAdjust, mb_substr($text, 0, $i));
3389
+
3390
+ $info = array('x' => $tmp[0], 'y' => $tmp[1], 'angle' => $angle, 'status' => 'end', 'p' => $parm, 'nCallback' => $this->nCallback);
3391
+ $x = $tmp[0];
3392
+ $y = $tmp[1];
3393
+ $ret = $this->$func($info);
3394
+
3395
+ if (is_array($ret)) {
3396
+ // then the return from the callback function could set the position, to start with, later will do font colour, and font
3397
+ foreach($ret as $rk => $rv) {
3398
+ switch ($rk) {
3399
+ case 'x':
3400
+ case 'y':
3401
+ $$rk = $rv;
3402
+ break;
3403
+ }
3404
+ }
3405
+ }
3406
+
3407
+ // also remove from to the stack
3408
+ // for simplicity, just take from the end, fix this another day
3409
+ $this->nCallback--;
3410
+ if ($this->nCallback<0) {
3411
+ $this->nCallBack = 0;
3412
+ }
3413
+ }
3414
+ }
3415
+ }
3416
+ break;
3417
+ }
3418
+ break;
3419
+
3420
+ case 'b':
3421
+ case 'i':
3422
+ $j++;
3423
+ if ($text[$j] === '>') {
3424
+ $this->currentTextState.= $text[$j-1];
3425
+ $directive = $j-$i+1;
3426
+ }
3427
+ break;
3428
+
3429
+ case 'C':
3430
+ $noClose = 1;
3431
+ case 'c':
3432
+ // this this might be a callback function
3433
+ $j++;
3434
+ $k = mb_strpos($text, '>', $j);
3435
+
3436
+ if ($k !== false && $text[$j] === ':') {
3437
+ // then this will be treated as a callback directive
3438
+ $directive = $k-$i+1;
3439
+
3440
+ $f = 0;
3441
+
3442
+ // split the remainder on colons to get the function name and the paramater
3443
+ // $bits = explode(':',substr($text,$j+1,$k-$j-1));
3444
+ $tmp = mb_substr($text, $j+1, $k-$j-1);
3445
+ $b1 = mb_strpos($tmp, ':');
3446
+
3447
+ if ($b1 !== false) {
3448
+ $func = mb_substr($tmp, 0, $b1);
3449
+ $parm = mb_substr($tmp, $b1+1);
3450
+ } else {
3451
+ $func = $tmp;
3452
+ $parm = '';
3453
+ }
3454
+
3455
+ if (!isset($func) || !mb_strlen(trim($func), '8bit')) {
3456
+ $directive = 0;
3457
+ } else {
3458
+ // only call the function if this is the final call, ie, the one actually doing printing, not measurement
3459
+ if ($final) {
3460
+ // need to assess the text position, calculate the text width to this point
3461
+ // can use getTextWidth to find the text width I think
3462
+ // also add the text height and descender
3463
+ $tmp = $this->PRVTgetTextPosition($x, $y, $angle, $size, $wordSpaceAdjust, mb_substr($text, 0, $i));
3464
+
3465
+ $info = array(
3466
+ 'x' => $tmp[0],
3467
+ 'y' => $tmp[1],
3468
+ 'angle' => $angle,
3469
+ 'status' => 'start',
3470
+ 'p' => $parm,
3471
+ 'f' => $func,
3472
+ 'height' => $this->getFontHeight($size),
3473
+ 'descender' => $this->getFontDescender($size)
3474
+ );
3475
+ $x = $tmp[0];
3476
+ $y = $tmp[1];
3477
+
3478
+ if (!isset($noClose) || !$noClose) {
3479
+ // only add to the stack if this is a small 'c', therefore is a start-stop pair
3480
+ $this->nCallback++;
3481
+ $info['nCallback'] = $this->nCallback;
3482
+ $this->callback[$this->nCallback] = $info;
3483
+ }
3484
+
3485
+ $ret = $this->$func($info);
3486
+ if (is_array($ret)) {
3487
+ // then the return from the callback function could set the position, to start with, later will do font colour, and font
3488
+ foreach($ret as $rk => $rv) {
3489
+ switch ($rk) {
3490
+ case 'x':
3491
+ case 'y':
3492
+ $$rk = $rv;
3493
+ break;
3494
+ }
3495
+ }
3496
+ }
3497
+ }
3498
+ }
3499
+ }
3500
+ break;
3501
+ }
3502
+ }
3503
+
3504
+ return $directive;
3505
+ }
3506
+
3507
+ /**
3508
+ * Callback method used by smallCaps
3509
+ *
3510
+ * @param array $matches
3511
+ * @return string
3512
+ */
3513
+ function toUpper($matches) {
3514
+ return mb_strtoupper($matches[0]);
3515
+ }
3516
+
3517
+ function concatMatches($matches) {
3518
+ $str = "";
3519
+ foreach($matches as $match){
3520
+ $str .= $match[0];
3521
+ }
3522
+ return $str;
3523
+ }
3524
+
3525
+ /**
3526
+ * add text to the document, at a specified location, size and angle on the page
3527
+ */
3528
+ function registerText($font, $text) {
3529
+ if ( !$this->isUnicode || in_array(mb_strtolower(basename($font)), self::$coreFonts) ) {
3530
+ return;
3531
+ }
3532
+
3533
+ if ( !isset($this->stringSubsets[$font]) ) {
3534
+ $this->stringSubsets[$font] = array();
3535
+ }
3536
+
3537
+ $this->stringSubsets[$font] = array_unique(array_merge($this->stringSubsets[$font], $this->utf8toCodePointsArray($text)));
3538
+ }
3539
+
3540
+ /**
3541
+ * add text to the document, at a specified location, size and angle on the page
3542
+ */
3543
+ function addText($x, $y, $size, $text, $angle = 0, $wordSpaceAdjust = 0, $charSpaceAdjust = 0, $smallCaps = false) {
3544
+ if (!$this->numFonts) {
3545
+ $this->selectFont($this->defaultFont);
3546
+ }
3547
+
3548
+ $text = str_replace(array("\r", "\n"), "", $text);
3549
+
3550
+ if ( $smallCaps ) {
3551
+ preg_match_all("/(\P{Ll}+)/u", $text, $matches, PREG_SET_ORDER);
3552
+ $lower = $this->concatMatches($matches);
3553
+ d($lower);
3554
+
3555
+ preg_match_all("/(\p{Ll}+)/u", $text, $matches, PREG_SET_ORDER);
3556
+ $other = $this->concatMatches($matches);
3557
+ d($other);
3558
+
3559
+ //$text = preg_replace_callback("/\p{Ll}/u", array($this, "toUpper"), $text);
3560
+ }
3561
+
3562
+ // if there are any open callbacks, then they should be called, to show the start of the line
3563
+ if ($this->nCallback>0) {
3564
+ for ($i = $this->nCallback;$i>0;$i--) {
3565
+ // call each function
3566
+ $info = array('x' => $x,
3567
+ 'y' => $y,
3568
+ 'angle' => $angle,
3569
+ 'status' => 'sol',
3570
+ 'p' => $this->callback[$i]['p'],
3571
+ 'nCallback' => $this->callback[$i]['nCallback'],
3572
+ 'height' => $this->callback[$i]['height'],
3573
+ 'descender' => $this->callback[$i]['descender']);
3574
+
3575
+ $func = $this->callback[$i]['f'];
3576
+ $this->$func($info);
3577
+ }
3578
+ }
3579
+
3580
+ if ($angle == 0) {
3581
+ $this->objects[$this->currentContents]['c'].= sprintf("\nBT %.3F %.3F Td", $x, $y);
3582
+ } else {
3583
+ $a = deg2rad((float)$angle);
3584
+ $this->objects[$this->currentContents]['c'].=
3585
+ sprintf("\nBT %.3F %.3F %.3F %.3F %.3F %.3F Tm", cos($a), -sin($a), sin($a), cos($a), $x, $y);
3586
+ }
3587
+
3588
+ if ($wordSpaceAdjust != 0 || $wordSpaceAdjust != $this->wordSpaceAdjust) {
3589
+ $this->wordSpaceAdjust = $wordSpaceAdjust;
3590
+ $this->objects[$this->currentContents]['c'].= sprintf(" %.3F Tw", $wordSpaceAdjust);
3591
+ }
3592
+
3593
+ if ($charSpaceAdjust != 0 || $charSpaceAdjust != $this->charSpaceAdjust) {
3594
+ $this->charSpaceAdjust = $charSpaceAdjust;
3595
+ $this->objects[$this->currentContents]['c'].= sprintf(" %.3F Tc", $charSpaceAdjust);
3596
+ }
3597
+
3598
+ $len = mb_strlen($text);
3599
+ $start = 0;
3600
+
3601
+ /*
3602
+ for ($i = 0;$i<$len;$i++){
3603
+ $f = 1;
3604
+ $directive = 0; //$this->PRVTcheckTextDirective($text,$i,$f);
3605
+ if ($directive){
3606
+ // then we should write what we need to
3607
+ if ($i>$start){
3608
+ $part = mb_substr($text,$start,$i-$start);
3609
+ $this->objects[$this->currentContents]['c'] .= ' /F'.$this->currentFontNum.' '.sprintf('%.1F',$size).' Tf ';
3610
+ $this->objects[$this->currentContents]['c'] .= ' ('.$this->filterText($part, false).') Tj';
3611
+ }
3612
+ if ($f){
3613
+ // then there was nothing drastic done here, restore the contents
3614
+ $this->setCurrentFont();
3615
+ } else {
3616
+ $this->objects[$this->currentContents]['c'] .= ' ET';
3617
+ $f = 1;
3618
+ $xp = $x;
3619
+ $yp = $y;
3620
+ $directive = 0; //$this->PRVTcheckTextDirective1($text,$i,$f,1,$xp,$yp,$size,$angle,$wordSpaceAdjust);
3621
+
3622
+ // restart the text object
3623
+ if ($angle == 0){
3624
+ $this->objects[$this->currentContents]['c'] .= "\n".'BT '.sprintf('%.3F',$xp).' '.sprintf('%.3F',$yp).' Td';
3625
+ } else {
3626
+ $a = deg2rad((float)$angle);
3627
+ $tmp = "\n".'BT ';
3628
+ $tmp .= sprintf('%.3F',cos($a)).' '.sprintf('%.3F',(-1.0*sin($a))).' '.sprintf('%.3F',sin($a)).' '.sprintf('%.3F',cos($a)).' ';
3629
+ $tmp .= sprintf('%.3F',$xp).' '.sprintf('%.3F',$yp).' Tm';
3630
+ $this->objects[$this->currentContents]['c'] .= $tmp;
3631
+ }
3632
+ if ($wordSpaceAdjust != 0 || $wordSpaceAdjust != $this->wordSpaceAdjust){
3633
+ $this->wordSpaceAdjust = $wordSpaceAdjust;
3634
+ $this->objects[$this->currentContents]['c'] .= ' '.sprintf('%.3F',$wordSpaceAdjust).' Tw';
3635
+ }
3636
+ }
3637
+ // and move the writing point to the next piece of text
3638
+ $i = $i+$directive-1;
3639
+ $start = $i+1;
3640
+ }
3641
+
3642
+ }
3643
+ */
3644
+ if ($start < $len) {
3645
+ $part = $text; // OAR - Don't need this anymore, given that $start always equals zero. substr($text, $start);
3646
+ $place_text = $this->filterText($part, false);
3647
+ // modify unicode text so that extra word spacing is manually implemented (bug #)
3648
+ $cf = $this->currentFont;
3649
+ if ($this->fonts[$cf]['isUnicode'] && $wordSpaceAdjust != 0) {
3650
+ $space_scale = 1000 / $size;
3651
+ //$place_text = str_replace(' ', ') ( ) '.($this->getTextWidth($size, chr(32), $wordSpaceAdjust)*-75).' (', $place_text);
3652
+ $place_text = str_replace(' ', ' ) '.(-round($space_scale*$wordSpaceAdjust)).' (', $place_text);
3653
+ }
3654
+ $this->objects[$this->currentContents]['c'].= " /F$this->currentFontNum ".sprintf('%.1F Tf ', $size);
3655
+ $this->objects[$this->currentContents]['c'].= " [($place_text)] TJ";
3656
+ }
3657
+
3658
+ $this->objects[$this->currentContents]['c'].= ' ET';
3659
+
3660
+ // if there are any open callbacks, then they should be called, to show the end of the line
3661
+ if ($this->nCallback>0) {
3662
+ for ($i = $this->nCallback;$i>0;$i--) {
3663
+ // call each function
3664
+ $tmp = $this->PRVTgetTextPosition($x, $y, $angle, $size, $wordSpaceAdjust, $text);
3665
+ $info = array(
3666
+ 'x' => $tmp[0],
3667
+ 'y' => $tmp[1],
3668
+ 'angle' => $angle,
3669
+ 'status' => 'eol',
3670
+ 'p' => $this->callback[$i]['p'],
3671
+ 'nCallback' => $this->callback[$i]['nCallback'],
3672
+ 'height' => $this->callback[$i]['height'],
3673
+ 'descender' => $this->callback[$i]['descender']
3674
+ );
3675
+ $func = $this->callback[$i]['f'];
3676
+ $this->$func($info);
3677
+ }
3678
+ }
3679
+ }
3680
+
3681
+ /**
3682
+ * calculate how wide a given text string will be on a page, at a given size.
3683
+ * this can be called externally, but is alse used by the other class functions
3684
+ */
3685
+ function getTextWidth($size, $text, $word_spacing = 0, $char_spacing = 0) {
3686
+ static $ord_cache = array();
3687
+
3688
+ // this function should not change any of the settings, though it will need to
3689
+ // track any directives which change during calculation, so copy them at the start
3690
+ // and put them back at the end.
3691
+ $store_currentTextState = $this->currentTextState;
3692
+
3693
+ if (!$this->numFonts) {
3694
+ $this->selectFont($this->defaultFont);
3695
+ }
3696
+
3697
+ $text = str_replace(array("\r", "\n"), "", $text);
3698
+
3699
+ // converts a number or a float to a string so it can get the width
3700
+ $text = "$text";
3701
+
3702
+ // hmm, this is where it all starts to get tricky - use the font information to
3703
+ // calculate the width of each character, add them up and convert to user units
3704
+ $w = 0;
3705
+ $cf = $this->currentFont;
3706
+ $current_font = $this->fonts[$cf];
3707
+ $space_scale = 1000 / $size;
3708
+ $n_spaces = 0;
3709
+
3710
+ if ( $current_font['isUnicode']) {
3711
+ // for Unicode, use the code points array to calculate width rather
3712
+ // than just the string itself
3713
+ $unicode = $this->utf8toCodePointsArray($text);
3714
+
3715
+ foreach ($unicode as $char) {
3716
+ // check if we have to replace character
3717
+ if ( isset($current_font['differences'][$char])) {
3718
+ $char = $current_font['differences'][$char];
3719
+ }
3720
+
3721
+ if ( isset($current_font['C'][$char]) ) {
3722
+ $char_width = $current_font['C'][$char];
3723
+
3724
+ // add the character width
3725
+ $w += $char_width;
3726
+
3727
+ // add additional padding for space
3728
+ if ( isset($current_font['codeToName'][$char]) && $current_font['codeToName'][$char] === 'space' ) { // Space
3729
+ $w += $word_spacing * $space_scale;
3730
+ $n_spaces++;
3731
+ }
3732
+ }
3733
+ }
3734
+
3735
+ // add additionnal char spacing
3736
+ if ( $char_spacing != 0 ) {
3737
+ $w += $char_spacing * $space_scale * (count($unicode) + $n_spaces);
3738
+ }
3739
+
3740
+ } else {
3741
+ // If CPDF is in Unicode mode but the current font does not support Unicode we need to convert the character set to Windows-1252
3742
+ if ( $this->isUnicode ) {
3743
+ $text = mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
3744
+ }
3745
+
3746
+ $len = mb_strlen($text, 'Windows-1252');
3747
+
3748
+ for ($i = 0; $i < $len; $i++) {
3749
+ $c = $text[$i];
3750
+ $char = isset($ord_cache[$c]) ? $ord_cache[$c] : ($ord_cache[$c] = ord($c));
3751
+
3752
+ // check if we have to replace character
3753
+ if ( isset($current_font['differences'][$char])) {
3754
+ $char = $current_font['differences'][$char];
3755
+ }
3756
+
3757
+ if ( isset($current_font['C'][$char]) ) {
3758
+ $char_width = $current_font['C'][$char];
3759
+
3760
+ // add the character width
3761
+ $w += $char_width;
3762
+
3763
+ // add additional padding for space
3764
+ if ( isset($current_font['codeToName'][$char]) && $current_font['codeToName'][$char] === 'space' ) { // Space
3765
+ $w += $word_spacing * $space_scale;
3766
+ $n_spaces++;
3767
+ }
3768
+ }
3769
+ }
3770
+
3771
+ // add additionnal char spacing
3772
+ if ( $char_spacing != 0 ) {
3773
+ $w += $char_spacing * $space_scale * ($len + $n_spaces);
3774
+ }
3775
+ }
3776
+
3777
+ $this->currentTextState = $store_currentTextState;
3778
+ $this->setCurrentFont();
3779
+
3780
+ return $w*$size/1000;
3781
+ }
3782
+
3783
+ /**
3784
+ * do a part of the calculation for sorting out the justification of the text
3785
+ *
3786
+ * @access private
3787
+ */
3788
+ function PRVTadjustWrapText($text, $actual, $width, &$x, &$adjust, $justification) {
3789
+ switch ($justification) {
3790
+ case 'left':
3791
+ return;
3792
+
3793
+ case 'right':
3794
+ $x+= $width-$actual;
3795
+ break;
3796
+
3797
+ case 'center':
3798
+ case 'centre':
3799
+ $x+= ($width-$actual) /2;
3800
+ break;
3801
+
3802
+ case 'full':
3803
+ // count the number of words
3804
+ $words = explode(' ', $text);
3805
+ $nspaces = count($words) -1;
3806
+
3807
+ if ($nspaces>0) {
3808
+ $adjust = ($width-$actual) /$nspaces;
3809
+ } else {
3810
+ $adjust = 0;
3811
+ }
3812
+ break;
3813
+ }
3814
+ }
3815
+
3816
+ /**
3817
+ * add text to the page, but ensure that it fits within a certain width
3818
+ * if it does not fit then put in as much as possible, splitting at word boundaries
3819
+ * and return the remainder.
3820
+ * justification and angle can also be specified for the text
3821
+ */
3822
+ function addTextWrap($x, $y, $width, $size, $text, $justification = 'left', $angle = 0, $test = 0) {
3823
+ // TODO - need to support Unicode
3824
+ $cf = $this->currentFont;
3825
+ if ($this->fonts[$cf]['isUnicode']) {
3826
+ die("addTextWrap does not support Unicode yet!");
3827
+ }
3828
+
3829
+ // this will display the text, and if it goes beyond the width $width, will backtrack to the
3830
+ // previous space or hyphen, and return the remainder of the text.
3831
+
3832
+ // $justification can be set to 'left','right','center','centre','full'
3833
+
3834
+ // need to store the initial text state, as this will change during the width calculation
3835
+ // but will need to be re-set before printing, so that the chars work out right
3836
+ $store_currentTextState = $this->currentTextState;
3837
+
3838
+ if (!$this->numFonts) {
3839
+ $this->selectFont($this->defaultFont);
3840
+ }
3841
+
3842
+ if ($width <= 0) {
3843
+ // error, pretend it printed ok, otherwise risking a loop
3844
+ return '';
3845
+ }
3846
+
3847
+ $w = 0;
3848
+ $break = 0;
3849
+ $breakWidth = 0;
3850
+ $len = mb_strlen($text);
3851
+ $cf = $this->currentFont;
3852
+ $tw = $width/$size*1000;
3853
+
3854
+ for ($i = 0;$i<$len;$i++) {
3855
+ $f = 1;
3856
+ $directive = 0;
3857
+ //$this->PRVTcheckTextDirective($text,$i,$f);
3858
+ if ($directive) {
3859
+ if ($f) {
3860
+ $this->setCurrentFont();
3861
+ $cf = $this->currentFont;
3862
+ }
3863
+
3864
+ $i = $i+$directive-1;
3865
+ } else {
3866
+ $cOrd = ord($text[$i]);
3867
+
3868
+ if (isset($this->fonts[$cf]['differences'][$cOrd])) {
3869
+ // then this character is being replaced by another
3870
+ $cOrd2 = $this->fonts[$cf]['differences'][$cOrd];
3871
+ } else {
3872
+ $cOrd2 = $cOrd;
3873
+ }
3874
+
3875
+ if (isset($this->fonts[$cf]['C'][$cOrd2])) {
3876
+ $w+= $this->fonts[$cf]['C'][$cOrd2];
3877
+ }
3878
+
3879
+ if ($w>$tw) {
3880
+ // then we need to truncate this line
3881
+ if ($break>0) {
3882
+ // then we have somewhere that we can split :)
3883
+ if ($text[$break] === ' ') {
3884
+ $tmp = mb_substr($text, 0, $break);
3885
+ } else {
3886
+ $tmp = mb_substr($text, 0, $break+1);
3887
+ }
3888
+
3889
+ $adjust = 0;
3890
+ $this->PRVTadjustWrapText($tmp, $breakWidth, $width, $x, $adjust, $justification);
3891
+
3892
+ // reset the text state
3893
+ $this->currentTextState = $store_currentTextState;
3894
+ $this->setCurrentFont();
3895
+
3896
+ if (!$test) {
3897
+ $this->addText($x, $y, $size, $tmp, $angle, $adjust);
3898
+ }
3899
+
3900
+ return mb_substr($text, $break+1);
3901
+ } else {
3902
+ // just split before the current character
3903
+ $tmp = mb_substr($text, 0, $i);
3904
+ $adjust = 0;
3905
+ $ctmp = ord($text[$i]);
3906
+
3907
+ if (isset($this->fonts[$cf]['differences'][$ctmp])) {
3908
+ $ctmp = $this->fonts[$cf]['differences'][$ctmp];
3909
+ }
3910
+
3911
+ $tmpw = ($w-$this->fonts[$cf]['C'][$ctmp]) *$size/1000;
3912
+ $this->PRVTadjustWrapText($tmp, $tmpw, $width, $x, $adjust, $justification);
3913
+
3914
+ // reset the text state
3915
+ $this->currentTextState = $store_currentTextState;
3916
+ $this->setCurrentFont();
3917
+
3918
+ if (!$test) {
3919
+ $this->addText($x, $y, $size, $tmp, $angle, $adjust);
3920
+ }
3921
+
3922
+ return mb_substr($text, $i);
3923
+ }
3924
+ }
3925
+
3926
+ if ($text[$i] === '-') {
3927
+ $break = $i;
3928
+ $breakWidth = $w*$size/1000;
3929
+ }
3930
+
3931
+ if ($text[$i] === ' ') {
3932
+ $break = $i;
3933
+ $ctmp = ord($text[$i]);
3934
+
3935
+ if (isset($this->fonts[$cf]['differences'][$ctmp])) {
3936
+ $ctmp = $this->fonts[$cf]['differences'][$ctmp];
3937
+ }
3938
+
3939
+ $breakWidth = ($w-$this->fonts[$cf]['C'][$ctmp]) *$size/1000;
3940
+ }
3941
+ }
3942
+ }
3943
+
3944
+ // then there was no need to break this line
3945
+ if ($justification === 'full') {
3946
+ $justification = 'left';
3947
+ }
3948
+
3949
+ $adjust = 0;
3950
+ $tmpw = $w*$size/1000;
3951
+
3952
+ $this->PRVTadjustWrapText($text, $tmpw, $width, $x, $adjust, $justification);
3953
+
3954
+ // reset the text state
3955
+ $this->currentTextState = $store_currentTextState;
3956
+ $this->setCurrentFont();
3957
+
3958
+ if (!$test) {
3959
+ $this->addText($x, $y, $size, $text, $angle, $adjust);
3960
+ }
3961
+
3962
+ return '';
3963
+ }
3964
+
3965
+ /**
3966
+ * this will be called at a new page to return the state to what it was on the
3967
+ * end of the previous page, before the stack was closed down
3968
+ * This is to get around not being able to have open 'q' across pages
3969
+ *
3970
+ */
3971
+ function saveState($pageEnd = 0) {
3972
+ if ($pageEnd) {
3973
+ // this will be called at a new page to return the state to what it was on the
3974
+ // end of the previous page, before the stack was closed down
3975
+ // This is to get around not being able to have open 'q' across pages
3976
+ $opt = $this->stateStack[$pageEnd];
3977
+ // ok to use this as stack starts numbering at 1
3978
+ $this->setColor($opt['col'], true);
3979
+ $this->setStrokeColor($opt['str'], true);
3980
+ $this->objects[$this->currentContents]['c'].= "\n".$opt['lin'];
3981
+ // $this->currentLineStyle = $opt['lin'];
3982
+ } else {
3983
+ $this->nStateStack++;
3984
+ $this->stateStack[$this->nStateStack] = array(
3985
+ 'col' => $this->currentColour,
3986
+ 'str' => $this->currentStrokeColour,
3987
+ 'lin' => $this->currentLineStyle
3988
+ );
3989
+ }
3990
+
3991
+ $this->save();
3992
+ }
3993
+
3994
+ /**
3995
+ * restore a previously saved state
3996
+ */
3997
+ function restoreState($pageEnd = 0) {
3998
+ if (!$pageEnd) {
3999
+ $n = $this->nStateStack;
4000
+ $this->currentColour = $this->stateStack[$n]['col'];
4001
+ $this->currentStrokeColour = $this->stateStack[$n]['str'];
4002
+ $this->objects[$this->currentContents]['c'].= "\n".$this->stateStack[$n]['lin'];
4003
+ $this->currentLineStyle = $this->stateStack[$n]['lin'];
4004
+ $this->stateStack[$n] = null;
4005
+ unset($this->stateStack[$n]);
4006
+ $this->nStateStack--;
4007
+ }
4008
+
4009
+ $this->restore();
4010
+ }
4011
+
4012
+ /**
4013
+ * make a loose object, the output will go into this object, until it is closed, then will revert to
4014
+ * the current one.
4015
+ * this object will not appear until it is included within a page.
4016
+ * the function will return the object number
4017
+ */
4018
+ function openObject() {
4019
+ $this->nStack++;
4020
+ $this->stack[$this->nStack] = array('c' => $this->currentContents, 'p' => $this->currentPage);
4021
+ // add a new object of the content type, to hold the data flow
4022
+ $this->numObj++;
4023
+ $this->o_contents($this->numObj, 'new');
4024
+ $this->currentContents = $this->numObj;
4025
+ $this->looseObjects[$this->numObj] = 1;
4026
+
4027
+ return $this->numObj;
4028
+ }
4029
+
4030
+ /**
4031
+ * open an existing object for editing
4032
+ */
4033
+ function reopenObject($id) {
4034
+ $this->nStack++;
4035
+ $this->stack[$this->nStack] = array('c' => $this->currentContents, 'p' => $this->currentPage);
4036
+ $this->currentContents = $id;
4037
+
4038
+ // also if this object is the primary contents for a page, then set the current page to its parent
4039
+ if (isset($this->objects[$id]['onPage'])) {
4040
+ $this->currentPage = $this->objects[$id]['onPage'];
4041
+ }
4042
+ }
4043
+
4044
+ /**
4045
+ * close an object
4046
+ */
4047
+ function closeObject() {
4048
+ // close the object, as long as there was one open in the first place, which will be indicated by
4049
+ // an objectId on the stack.
4050
+ if ($this->nStack>0) {
4051
+ $this->currentContents = $this->stack[$this->nStack]['c'];
4052
+ $this->currentPage = $this->stack[$this->nStack]['p'];
4053
+ $this->nStack--;
4054
+ // easier to probably not worry about removing the old entries, they will be overwritten
4055
+ // if there are new ones.
4056
+ }
4057
+ }
4058
+
4059
+ /**
4060
+ * stop an object from appearing on pages from this point on
4061
+ */
4062
+ function stopObject($id) {
4063
+ // if an object has been appearing on pages up to now, then stop it, this page will
4064
+ // be the last one that could contian it.
4065
+ if (isset($this->addLooseObjects[$id])) {
4066
+ $this->addLooseObjects[$id] = '';
4067
+ }
4068
+ }
4069
+
4070
+ /**
4071
+ * after an object has been created, it wil only show if it has been added, using this function.
4072
+ */
4073
+ function addObject($id, $options = 'add') {
4074
+ // add the specified object to the page
4075
+ if (isset($this->looseObjects[$id]) && $this->currentContents != $id) {
4076
+ // then it is a valid object, and it is not being added to itself
4077
+ switch ($options) {
4078
+ case 'all':
4079
+ // then this object is to be added to this page (done in the next block) and
4080
+ // all future new pages.
4081
+ $this->addLooseObjects[$id] = 'all';
4082
+
4083
+ case 'add':
4084
+ if (isset($this->objects[$this->currentContents]['onPage'])) {
4085
+ // then the destination contents is the primary for the page
4086
+ // (though this object is actually added to that page)
4087
+ $this->o_page($this->objects[$this->currentContents]['onPage'], 'content', $id);
4088
+ }
4089
+ break;
4090
+
4091
+ case 'even':
4092
+ $this->addLooseObjects[$id] = 'even';
4093
+ $pageObjectId = $this->objects[$this->currentContents]['onPage'];
4094
+ if ($this->objects[$pageObjectId]['info']['pageNum']%2 == 0) {
4095
+ $this->addObject($id);
4096
+ // hacky huh :)
4097
+ }
4098
+ break;
4099
+
4100
+ case 'odd':
4101
+ $this->addLooseObjects[$id] = 'odd';
4102
+ $pageObjectId = $this->objects[$this->currentContents]['onPage'];
4103
+ if ($this->objects[$pageObjectId]['info']['pageNum']%2 == 1) {
4104
+ $this->addObject($id);
4105
+ // hacky huh :)
4106
+ }
4107
+ break;
4108
+
4109
+ case 'next':
4110
+ $this->addLooseObjects[$id] = 'all';
4111
+ break;
4112
+
4113
+ case 'nexteven':
4114
+ $this->addLooseObjects[$id] = 'even';
4115
+ break;
4116
+
4117
+ case 'nextodd':
4118
+ $this->addLooseObjects[$id] = 'odd';
4119
+ break;
4120
+ }
4121
+ }
4122
+ }
4123
+
4124
+ /**
4125
+ * return a storable representation of a specific object
4126
+ */
4127
+ function serializeObject($id) {
4128
+ if ( array_key_exists($id, $this->objects))
4129
+ return var_export($this->objects[$id], true);
4130
+ }
4131
+
4132
+ /**
4133
+ * restore an object from its stored representation. returns its new object id.
4134
+ */
4135
+ function restoreSerializedObject($obj) {
4136
+ $obj_id = $this->openObject();
4137
+ eval('$this->objects[$obj_id] = ' . $obj . ';');
4138
+ $this->closeObject();
4139
+ return $obj_id;
4140
+ }
4141
+
4142
+ /**
4143
+ * add content to the documents info object
4144
+ */
4145
+ function addInfo($label, $value = 0) {
4146
+ // this will only work if the label is one of the valid ones.
4147
+ // modify this so that arrays can be passed as well.
4148
+ // if $label is an array then assume that it is key => value pairs
4149
+ // else assume that they are both scalar, anything else will probably error
4150
+ if (is_array($label)) {
4151
+ foreach ($label as $l => $v) {
4152
+ $this->o_info($this->infoObject, $l, $v);
4153
+ }
4154
+ } else {
4155
+ $this->o_info($this->infoObject, $label, $value);
4156
+ }
4157
+ }
4158
+
4159
+ /**
4160
+ * set the viewer preferences of the document, it is up to the browser to obey these.
4161
+ */
4162
+ function setPreferences($label, $value = 0) {
4163
+ // this will only work if the label is one of the valid ones.
4164
+ if (is_array($label)) {
4165
+ foreach ($label as $l => $v) {
4166
+ $this->o_catalog($this->catalogId, 'viewerPreferences', array($l => $v));
4167
+ }
4168
+ } else {
4169
+ $this->o_catalog($this->catalogId, 'viewerPreferences', array($label => $value));
4170
+ }
4171
+ }
4172
+
4173
+ /**
4174
+ * extract an integer from a position in a byte stream
4175
+ *
4176
+ * @access private
4177
+ */
4178
+ function PRVT_getBytes(&$data, $pos, $num) {
4179
+ // return the integer represented by $num bytes from $pos within $data
4180
+ $ret = 0;
4181
+ for ($i = 0;$i<$num;$i++) {
4182
+ $ret = $ret*256;
4183
+ $ret+= ord($data[$pos+$i]);
4184
+ }
4185
+
4186
+ return $ret;
4187
+ }
4188
+
4189
+ /**
4190
+ * Check if image already added to pdf image directory.
4191
+ * If yes, need not to create again (pass empty data)
4192
+ */
4193
+ function image_iscached($imgname) {
4194
+ return isset($this->imagelist[$imgname]);
4195
+ }
4196
+
4197
+ /**
4198
+ * add a PNG image into the document, from a GD object
4199
+ * this should work with remote files
4200
+ *
4201
+ * @param string $file The PNG file
4202
+ * @param float $x X position
4203
+ * @param float $y Y position
4204
+ * @param float $w Width
4205
+ * @param float $h Height
4206
+ * @param resource $img A GD resource
4207
+ * @param bool $is_mask true if the image is a mask
4208
+ * @param bool $mask true if the image is masked
4209
+ */
4210
+ function addImagePng($file, $x, $y, $w = 0, $h = 0, &$img, $is_mask = false, $mask = null) {
4211
+ //if already cached, need not to read again
4212
+ if ( isset($this->imagelist[$file]) ) {
4213
+ $data = null;
4214
+ }
4215
+ else {
4216
+ // Example for transparency handling on new image. Retain for current image
4217
+ // $tIndex = imagecolortransparent($img);
4218
+ // if ($tIndex > 0) {
4219
+ // $tColor = imagecolorsforindex($img, $tIndex);
4220
+ // $new_tIndex = imagecolorallocate($new_img, $tColor['red'], $tColor['green'], $tColor['blue']);
4221
+ // imagefill($new_img, 0, 0, $new_tIndex);
4222
+ // imagecolortransparent($new_img, $new_tIndex);
4223
+ // }
4224
+ // blending mode (literal/blending) on drawing into current image. not relevant when not saved or not drawn
4225
+ //imagealphablending($img, true);
4226
+
4227
+ //default, but explicitely set to ensure pdf compatibility
4228
+ imagesavealpha($img, false/*!$is_mask && !$mask*/);
4229
+
4230
+ $error = 0;
4231
+ //DEBUG_IMG_TEMP
4232
+ //debugpng
4233
+ if (DEBUGPNG) print '[addImagePng '.$file.']';
4234
+
4235
+ ob_start();
4236
+ @imagepng($img);
4237
+ $data = ob_get_clean();
4238
+
4239
+ if ($data == '') {
4240
+ $error = 1;
4241
+ $errormsg = 'trouble writing file from GD';
4242
+ //DEBUG_IMG_TEMP
4243
+ //debugpng
4244
+ if (DEBUGPNG) print 'trouble writing file from GD';
4245
+ }
4246
+
4247
+ if ($error) {
4248
+ $this->addMessage('PNG error - ('.$file.') '.$errormsg);
4249
+ return;
4250
+ }
4251
+ } //End isset($this->imagelist[$file]) (png Duplicate removal)
4252
+
4253
+ $this->addPngFromBuf($file, $x, $y, $w, $h, $data, $is_mask, $mask);
4254
+ }
4255
+
4256
+ protected function addImagePngAlpha($file, $x, $y, $w, $h, $byte) {
4257
+ // generate images
4258
+ $img = imagecreatefrompng($file);
4259
+
4260
+ if ($img === false) {
4261
+ return;
4262
+ }
4263
+
4264
+ // FIXME The pixel transformation doesn't work well with 8bit PNGs
4265
+ $eight_bit = ($byte & 4) !== 4;
4266
+
4267
+ $wpx = imagesx($img);
4268
+ $hpx = imagesy($img);
4269
+
4270
+ imagesavealpha($img, false);
4271
+
4272
+ // create temp alpha file
4273
+ $tempfile_alpha = tempnam($this->tmp, "cpdf_img_");
4274
+ @unlink($tempfile_alpha);
4275
+ $tempfile_alpha = "$tempfile_alpha.png";
4276
+
4277
+ // create temp plain file
4278
+ $tempfile_plain = tempnam($this->tmp, "cpdf_img_");
4279
+ @unlink($tempfile_plain);
4280
+ $tempfile_plain = "$tempfile_plain.png";
4281
+
4282
+ $imgalpha = imagecreate($wpx, $hpx);
4283
+ imagesavealpha($imgalpha, false);
4284
+
4285
+ // generate gray scale palette (0 -> 255)
4286
+ for ($c = 0; $c < 256; ++$c) {
4287
+ imagecolorallocate($imgalpha, $c, $c, $c);
4288
+ }
4289
+
4290
+ // Use PECL gmagick + Graphics Magic to process transparent PNG images
4291
+ if (extension_loaded("gmagick")) {
4292
+ $gmagick = new Gmagick($file);
4293
+ $gmagick->setimageformat('png');
4294
+
4295
+ // Get opacity channel (negative of alpha channel)
4296
+ $alpha_channel_neg = clone $gmagick;
4297
+ $alpha_channel_neg->separateimagechannel(Gmagick::CHANNEL_OPACITY);
4298
+
4299
+ // Negate opacity channel
4300
+ $alpha_channel = new Gmagick();
4301
+ $alpha_channel->newimage($wpx, $hpx, "#FFFFFF", "png");
4302
+ $alpha_channel->compositeimage($alpha_channel_neg, Gmagick::COMPOSITE_DIFFERENCE, 0, 0);
4303
+ $alpha_channel->separateimagechannel(Gmagick::CHANNEL_RED);
4304
+ $alpha_channel->writeimage($tempfile_alpha);
4305
+
4306
+ // Cast to 8bit+palette
4307
+ $imgalpha_ = imagecreatefrompng($tempfile_alpha);
4308
+ imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
4309
+ imagedestroy($imgalpha_);
4310
+ imagepng($imgalpha, $tempfile_alpha);
4311
+
4312
+ // Make opaque image
4313
+ $color_channels = new Gmagick();
4314
+ $color_channels->newimage($wpx, $hpx, "#FFFFFF", "png");
4315
+ $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYRED, 0, 0);
4316
+ $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYGREEN, 0, 0);
4317
+ $color_channels->compositeimage($gmagick, Gmagick::COMPOSITE_COPYBLUE, 0, 0);
4318
+ $color_channels->writeimage($tempfile_plain);
4319
+
4320
+ $imgplain = imagecreatefrompng($tempfile_plain);
4321
+ }
4322
+
4323
+ // Use PECL imagick + ImageMagic to process transparent PNG images
4324
+ elseif (extension_loaded("imagick")) {
4325
+ $imagick = new Imagick($file);
4326
+ $imagick->setFormat('png');
4327
+
4328
+ // Get opacity channel (negative of alpha channel)
4329
+ $alpha_channel = clone $imagick;
4330
+ $alpha_channel->separateImageChannel(Imagick::CHANNEL_ALPHA);
4331
+ $alpha_channel->negateImage(true);
4332
+ $alpha_channel->writeImage($tempfile_alpha);
4333
+
4334
+ // Cast to 8bit+palette
4335
+ $imgalpha_ = imagecreatefrompng($tempfile_alpha);
4336
+ imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
4337
+ imagedestroy($imgalpha_);
4338
+ imagepng($imgalpha, $tempfile_alpha);
4339
+
4340
+ // Make opaque image
4341
+ $color_channels = new Imagick();
4342
+ $color_channels->newImage($wpx, $hpx, "#FFFFFF", "png");
4343
+ $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYRED, 0, 0);
4344
+ $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYGREEN, 0, 0);
4345
+ $color_channels->compositeImage($imagick, Imagick::COMPOSITE_COPYBLUE, 0, 0);
4346
+ $color_channels->writeImage($tempfile_plain);
4347
+
4348
+ $imgplain = imagecreatefrompng($tempfile_plain);
4349
+ }
4350
+ else {
4351
+ // allocated colors cache
4352
+ $allocated_colors = array();
4353
+
4354
+ // extract alpha channel
4355
+ for ($xpx = 0; $xpx < $wpx; ++$xpx) {
4356
+ for ($ypx = 0; $ypx < $hpx; ++$ypx) {
4357
+ $color = imagecolorat($img, $xpx, $ypx);
4358
+ $col = imagecolorsforindex($img, $color);
4359
+ $alpha = $col['alpha'];
4360
+
4361
+ if ($eight_bit) {
4362
+ // with gamma correction
4363
+ $gammacorr = 2.2;
4364
+ $pixel = pow((((127 - $alpha) * 255 / 127) / 255), $gammacorr) * 255;
4365
+ }
4366
+
4367
+ else {
4368
+ // without gamma correction
4369
+ $pixel = (127 - $alpha) * 2;
4370
+
4371
+ $key = $col['red'].$col['green'].$col['blue'];
4372
+
4373
+ if (!isset($allocated_colors[$key])) {
4374
+ $pixel_img = imagecolorallocate($img, $col['red'], $col['green'], $col['blue']);
4375
+ $allocated_colors[$key] = $pixel_img;
4376
+ }
4377
+ else {
4378
+ $pixel_img = $allocated_colors[$key];
4379
+ }
4380
+
4381
+ imagesetpixel($img, $xpx, $ypx, $pixel_img);
4382
+ }
4383
+
4384
+ imagesetpixel($imgalpha, $xpx, $ypx, $pixel);
4385
+ }
4386
+ }
4387
+
4388
+ // extract image without alpha channel
4389
+ $imgplain = imagecreatetruecolor($wpx, $hpx);
4390
+ imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx);
4391
+ imagedestroy($img);
4392
+
4393
+ imagepng($imgalpha, $tempfile_alpha);
4394
+ imagepng($imgplain, $tempfile_plain);
4395
+ }
4396
+
4397
+ // embed mask image
4398
+ $this->addImagePng($tempfile_alpha, $x, $y, $w, $h, $imgalpha, true);
4399
+ imagedestroy($imgalpha);
4400
+
4401
+ // embed image, masked with previously embedded mask
4402
+ $this->addImagePng($tempfile_plain, $x, $y, $w, $h, $imgplain, false, true);
4403
+ imagedestroy($imgplain);
4404
+
4405
+ // remove temp files
4406
+ unlink($tempfile_alpha);
4407
+ unlink($tempfile_plain);
4408
+ }
4409
+
4410
+ /**
4411
+ * add a PNG image into the document, from a file
4412
+ * this should work with remote files
4413
+ */
4414
+ function addPngFromFile($file, $x, $y, $w = 0, $h = 0) {
4415
+ //if already cached, need not to read again
4416
+ if ( isset($this->imagelist[$file]) ) {
4417
+ $img = null;
4418
+ }
4419
+
4420
+ else {
4421
+ $info = file_get_contents ($file, false, null, 24, 5);
4422
+ $meta = unpack("CbitDepth/CcolorType/CcompressionMethod/CfilterMethod/CinterlaceMethod", $info);
4423
+ $bit_depth = $meta["bitDepth"];
4424
+ $color_type = $meta["colorType"];
4425
+
4426
+ // http://www.w3.org/TR/PNG/#11IHDR
4427
+ // 3 => indexed
4428
+ // 4 => greyscale with alpha
4429
+ // 6 => fullcolor with alpha
4430
+ $is_alpha = in_array($color_type, array(4, 6)) || ($color_type == 3 && $bit_depth != 4);
4431
+
4432
+ if ($is_alpha) { // exclude grayscale alpha
4433
+ return $this->addImagePngAlpha($file, $x, $y, $w, $h, $color_type);
4434
+ }
4435
+
4436
+ //png files typically contain an alpha channel.
4437
+ //pdf file format or class.pdf does not support alpha blending.
4438
+ //on alpha blended images, more transparent areas have a color near black.
4439
+ //This appears in the result on not storing the alpha channel.
4440
+ //Correct would be the box background image or its parent when transparent.
4441
+ //But this would make the image dependent on the background.
4442
+ //Therefore create an image with white background and copy in
4443
+ //A more natural background than black is white.
4444
+ //Therefore create an empty image with white background and merge the
4445
+ //image in with alpha blending.
4446
+ $imgtmp = @imagecreatefrompng($file);
4447
+ if (!$imgtmp) {
4448
+ return;
4449
+ }
4450
+ $sx = imagesx($imgtmp);
4451
+ $sy = imagesy($imgtmp);
4452
+ $img = imagecreatetruecolor($sx,$sy);
4453
+ imagealphablending($img, true);
4454
+
4455
+ // @todo is it still needed ??
4456
+ $ti = imagecolortransparent($imgtmp);
4457
+ if ($ti >= 0) {
4458
+ $tc = imagecolorsforindex($imgtmp,$ti);
4459
+ $ti = imagecolorallocate($img,$tc['red'],$tc['green'],$tc['blue']);
4460
+ imagefill($img,0,0,$ti);
4461
+ imagecolortransparent($img, $ti);
4462
+ } else {
4463
+ imagefill($img,1,1,imagecolorallocate($img,255,255,255));
4464
+ }
4465
+
4466
+ imagecopy($img,$imgtmp,0,0,0,0,$sx,$sy);
4467
+ imagedestroy($imgtmp);
4468
+ }
4469
+ $this->addImagePng($file, $x, $y, $w, $h, $img);
4470
+
4471
+ if ( $img ) {
4472
+ imagedestroy($img);
4473
+ }
4474
+ }
4475
+
4476
+ /**
4477
+ * add a PNG image into the document, from a memory buffer of the file
4478
+ */
4479
+ function addPngFromBuf($file, $x, $y, $w = 0, $h = 0, &$data, $is_mask = false, $mask = null) {
4480
+ if ( isset($this->imagelist[$file]) ) {
4481
+ $data = null;
4482
+ $info['width'] = $this->imagelist[$file]['w'];
4483
+ $info['height'] = $this->imagelist[$file]['h'];
4484
+ $label = $this->imagelist[$file]['label'];
4485
+ }
4486
+
4487
+ else {
4488
+ if ($data == null) {
4489
+ $this->addMessage('addPngFromBuf error - ('.$imgname.') data not present!');
4490
+ return;
4491
+ }
4492
+
4493
+ $error = 0;
4494
+
4495
+ if (!$error) {
4496
+ $header = chr(137) .chr(80) .chr(78) .chr(71) .chr(13) .chr(10) .chr(26) .chr(10);
4497
+
4498
+ if (mb_substr($data, 0, 8, '8bit') != $header) {
4499
+ $error = 1;
4500
+
4501
+ if (DEBUGPNG) print '[addPngFromFile this file does not have a valid header '.$file.']';
4502
+
4503
+ $errormsg = 'this file does not have a valid header';
4504
+ }
4505
+ }
4506
+
4507
+ if (!$error) {
4508
+ // set pointer
4509
+ $p = 8;
4510
+ $len = mb_strlen($data, '8bit');
4511
+
4512
+ // cycle through the file, identifying chunks
4513
+ $haveHeader = 0;
4514
+ $info = array();
4515
+ $idata = '';
4516
+ $pdata = '';
4517
+
4518
+ while ($p < $len) {
4519
+ $chunkLen = $this->PRVT_getBytes($data, $p, 4);
4520
+ $chunkType = mb_substr($data, $p+4, 4, '8bit');
4521
+
4522
+ switch ($chunkType) {
4523
+ case 'IHDR':
4524
+ // this is where all the file information comes from
4525
+ $info['width'] = $this->PRVT_getBytes($data, $p+8, 4);
4526
+ $info['height'] = $this->PRVT_getBytes($data, $p+12, 4);
4527
+ $info['bitDepth'] = ord($data[$p+16]);
4528
+ $info['colorType'] = ord($data[$p+17]);
4529
+ $info['compressionMethod'] = ord($data[$p+18]);
4530
+ $info['filterMethod'] = ord($data[$p+19]);
4531
+ $info['interlaceMethod'] = ord($data[$p+20]);
4532
+
4533
+ //print_r($info);
4534
+ $haveHeader = 1;
4535
+ if ($info['compressionMethod'] != 0) {
4536
+ $error = 1;
4537
+
4538
+ //debugpng
4539
+ if (DEBUGPNG) print '[addPngFromFile unsupported compression method '.$file.']';
4540
+
4541
+ $errormsg = 'unsupported compression method';
4542
+ }
4543
+
4544
+ if ($info['filterMethod'] != 0) {
4545
+ $error = 1;
4546
+
4547
+ //debugpng
4548
+ if (DEBUGPNG) print '[addPngFromFile unsupported filter method '.$file.']';
4549
+
4550
+ $errormsg = 'unsupported filter method';
4551
+ }
4552
+ break;
4553
+
4554
+ case 'PLTE':
4555
+ $pdata.= mb_substr($data, $p+8, $chunkLen, '8bit');
4556
+ break;
4557
+
4558
+ case 'IDAT':
4559
+ $idata.= mb_substr($data, $p+8, $chunkLen, '8bit');
4560
+ break;
4561
+
4562
+ case 'tRNS':
4563
+ //this chunk can only occur once and it must occur after the PLTE chunk and before IDAT chunk
4564
+ //print "tRNS found, color type = ".$info['colorType']."\n";
4565
+ $transparency = array();
4566
+
4567
+ switch ($info['colorType']) {
4568
+ // indexed color, rbg
4569
+ case 3:
4570
+ /* corresponding to entries in the plte chunk
4571
+ Alpha for palette index 0: 1 byte
4572
+ Alpha for palette index 1: 1 byte
4573
+ ...etc...
4574
+ */
4575
+ // there will be one entry for each palette entry. up until the last non-opaque entry.
4576
+ // set up an array, stretching over all palette entries which will be o (opaque) or 1 (transparent)
4577
+ $transparency['type'] = 'indexed';
4578
+
4579
+ $numPalette = mb_strlen($pdata, '8bit')/3;
4580
+ $trans = 0;
4581
+
4582
+ for ($i = $chunkLen;$i >= 0;$i--) {
4583
+ if (ord($data[$p+8+$i]) == 0) {
4584
+ $trans = $i;
4585
+ }
4586
+ }
4587
+
4588
+ $transparency['data'] = $trans;
4589
+ break;
4590
+
4591
+ // grayscale
4592
+ case 0:
4593
+ /* corresponding to entries in the plte chunk
4594
+ Gray: 2 bytes, range 0 .. (2^bitdepth)-1
4595
+ */
4596
+ // $transparency['grayscale'] = $this->PRVT_getBytes($data,$p+8,2); // g = grayscale
4597
+ $transparency['type'] = 'indexed';
4598
+ $transparency['data'] = ord($data[$p+8+1]);
4599
+ break;
4600
+
4601
+ // truecolor
4602
+ case 2:
4603
+ /* corresponding to entries in the plte chunk
4604
+ Red: 2 bytes, range 0 .. (2^bitdepth)-1
4605
+ Green: 2 bytes, range 0 .. (2^bitdepth)-1
4606
+ Blue: 2 bytes, range 0 .. (2^bitdepth)-1
4607
+ */
4608
+ $transparency['r'] = $this->PRVT_getBytes($data, $p+8, 2);
4609
+ // r from truecolor
4610
+ $transparency['g'] = $this->PRVT_getBytes($data, $p+10, 2);
4611
+ // g from truecolor
4612
+ $transparency['b'] = $this->PRVT_getBytes($data, $p+12, 2);
4613
+ // b from truecolor
4614
+
4615
+ $transparency['type'] = 'color-key';
4616
+ break;
4617
+
4618
+ //unsupported transparency type
4619
+ default:
4620
+ if (DEBUGPNG) print '[addPngFromFile unsupported transparency type '.$file.']';
4621
+ break;
4622
+ }
4623
+
4624
+ // KS End new code
4625
+ break;
4626
+
4627
+ default:
4628
+ break;
4629
+ }
4630
+
4631
+ $p += $chunkLen+12;
4632
+ }
4633
+
4634
+ if (!$haveHeader) {
4635
+ $error = 1;
4636
+
4637
+ //debugpng
4638
+ if (DEBUGPNG) print '[addPngFromFile information header is missing '.$file.']';
4639
+
4640
+ $errormsg = 'information header is missing';
4641
+ }
4642
+
4643
+ if (isset($info['interlaceMethod']) && $info['interlaceMethod']) {
4644
+ $error = 1;
4645
+
4646
+ //debugpng
4647
+ if (DEBUGPNG) print '[addPngFromFile no support for interlaced images in pdf '.$file.']';
4648
+
4649
+ $errormsg = 'There appears to be no support for interlaced images in pdf.';
4650
+ }
4651
+ }
4652
+
4653
+ if (!$error && $info['bitDepth'] > 8) {
4654
+ $error = 1;
4655
+
4656
+ //debugpng
4657
+ if (DEBUGPNG) print '[addPngFromFile bit depth of 8 or less is supported '.$file.']';
4658
+
4659
+ $errormsg = 'only bit depth of 8 or less is supported';
4660
+ }
4661
+
4662
+ if (!$error) {
4663
+ switch ($info['colorType']) {
4664
+ case 3:
4665
+ $color = 'DeviceRGB';
4666
+ $ncolor = 1;
4667
+ break;
4668
+
4669
+ case 2:
4670
+ $color = 'DeviceRGB';
4671
+ $ncolor = 3;
4672
+ break;
4673
+
4674
+ case 0:
4675
+ $color = 'DeviceGray';
4676
+ $ncolor = 1;
4677
+ break;
4678
+
4679
+ default:
4680
+ $error = 1;
4681
+
4682
+ //debugpng
4683
+ if (DEBUGPNG) print '[addPngFromFile alpha channel not supported: '.$info['colorType'].' '.$file.']';
4684
+
4685
+ $errormsg = 'transparancey alpha channel not supported, transparency only supported for palette images.';
4686
+ }
4687
+ }
4688
+
4689
+ if ($error) {
4690
+ $this->addMessage('PNG error - ('.$file.') '.$errormsg);
4691
+ return;
4692
+ }
4693
+
4694
+ //print_r($info);
4695
+ // so this image is ok... add it in.
4696
+ $this->numImages++;
4697
+ $im = $this->numImages;
4698
+ $label = "I$im";
4699
+ $this->numObj++;
4700
+
4701
+ // $this->o_image($this->numObj,'new',array('label' => $label,'data' => $idata,'iw' => $w,'ih' => $h,'type' => 'png','ic' => $info['width']));
4702
+ $options = array(
4703
+ 'label' => $label,
4704
+ 'data' => $idata,
4705
+ 'bitsPerComponent' => $info['bitDepth'],
4706
+ 'pdata' => $pdata,
4707
+ 'iw' => $info['width'],
4708
+ 'ih' => $info['height'],
4709
+ 'type' => 'png',
4710
+ 'color' => $color,
4711
+ 'ncolor' => $ncolor,
4712
+ 'masked' => $mask,
4713
+ 'isMask' => $is_mask,
4714
+ );
4715
+
4716
+ if (isset($transparency)) {
4717
+ $options['transparency'] = $transparency;
4718
+ }
4719
+
4720
+ $this->o_image($this->numObj, 'new', $options);
4721
+ $this->imagelist[$file] = array('label' =>$label, 'w' => $info['width'], 'h' => $info['height']);
4722
+ }
4723
+
4724
+ if ($is_mask) {
4725
+ return;
4726
+ }
4727
+
4728
+ if ($w <= 0 && $h <= 0) {
4729
+ $w = $info['width'];
4730
+ $h = $info['height'];
4731
+ }
4732
+
4733
+ if ($w <= 0) {
4734
+ $w = $h/$info['height']*$info['width'];
4735
+ }
4736
+
4737
+ if ($h <= 0) {
4738
+ $h = $w*$info['height']/$info['width'];
4739
+ }
4740
+
4741
+ $this->objects[$this->currentContents]['c'].= sprintf("\nq\n%.3F 0 0 %.3F %.3F %.3F cm /%s Do\nQ", $w, $h, $x, $y, $label);
4742
+ }
4743
+
4744
+ /**
4745
+ * add a JPEG image into the document, from a file
4746
+ */
4747
+ function addJpegFromFile($img, $x, $y, $w = 0, $h = 0) {
4748
+ // attempt to add a jpeg image straight from a file, using no GD commands
4749
+ // note that this function is unable to operate on a remote file.
4750
+
4751
+ if (!file_exists($img)) {
4752
+ return;
4753
+ }
4754
+
4755
+ if ( $this->image_iscached($img) ) {
4756
+ $data = null;
4757
+ $imageWidth = $this->imagelist[$img]['w'];
4758
+ $imageHeight = $this->imagelist[$img]['h'];
4759
+ $channels = $this->imagelist[$img]['c'];
4760
+ }
4761
+ else {
4762
+ $tmp = getimagesize($img);
4763
+ $imageWidth = $tmp[0];
4764
+ $imageHeight = $tmp[1];
4765
+
4766
+ if ( isset($tmp['channels']) ) {
4767
+ $channels = $tmp['channels'];
4768
+ } else {
4769
+ $channels = 3;
4770
+ }
4771
+
4772
+ $data = file_get_contents($img);
4773
+ }
4774
+
4775
+ if ($w <= 0 && $h <= 0) {
4776
+ $w = $imageWidth;
4777
+ }
4778
+
4779
+ if ($w == 0) {
4780
+ $w = $h/$imageHeight*$imageWidth;
4781
+ }
4782
+
4783
+ if ($h == 0) {
4784
+ $h = $w*$imageHeight/$imageWidth;
4785
+ }
4786
+
4787
+ $this->addJpegImage_common($data, $x, $y, $w, $h, $imageWidth, $imageHeight, $channels, $img);
4788
+ }
4789
+
4790
+ /**
4791
+ * common code used by the two JPEG adding functions
4792
+ *
4793
+ * @access private
4794
+ */
4795
+ function addJpegImage_common(&$data, $x, $y, $w = 0, $h = 0, $imageWidth, $imageHeight, $channels = 3, $imgname) {
4796
+ if ( $this->image_iscached($imgname) ) {
4797
+ $label = $this->imagelist[$imgname]['label'];
4798
+ //debugpng
4799
+ //if (DEBUGPNG) print '[addJpegImage_common Duplicate '.$imgname.']';
4800
+
4801
+ } else {
4802
+ if ($data == null) {
4803
+ $this->addMessage('addJpegImage_common error - ('.$imgname.') data not present!');
4804
+ return;
4805
+ }
4806
+
4807
+ // note that this function is not to be called externally
4808
+ // it is just the common code between the GD and the file options
4809
+ $this->numImages++;
4810
+ $im = $this->numImages;
4811
+ $label = "I$im";
4812
+ $this->numObj++;
4813
+
4814
+ $this->o_image($this->numObj, 'new', array(
4815
+ 'label' => $label,
4816
+ 'data' => &$data,
4817
+ 'iw' => $imageWidth,
4818
+ 'ih' => $imageHeight,
4819
+ 'channels' => $channels
4820
+ ));
4821
+
4822
+ $this->imagelist[$imgname] = array('label' =>$label, 'w' => $imageWidth, 'h' => $imageHeight, 'c'=> $channels );
4823
+ }
4824
+
4825
+ $this->objects[$this->currentContents]['c'].= sprintf("\nq\n%.3F 0 0 %.3F %.3F %.3F cm /%s Do\nQ ", $w, $h, $x, $y, $label);
4826
+ }
4827
+
4828
+ /**
4829
+ * specify where the document should open when it first starts
4830
+ */
4831
+ function openHere($style, $a = 0, $b = 0, $c = 0) {
4832
+ // this function will open the document at a specified page, in a specified style
4833
+ // the values for style, and the required paramters are:
4834
+ // 'XYZ' left, top, zoom
4835
+ // 'Fit'
4836
+ // 'FitH' top
4837
+ // 'FitV' left
4838
+ // 'FitR' left,bottom,right
4839
+ // 'FitB'
4840
+ // 'FitBH' top
4841
+ // 'FitBV' left
4842
+ $this->numObj++;
4843
+ $this->o_destination($this->numObj, 'new', array('page' => $this->currentPage, 'type' => $style, 'p1' => $a, 'p2' => $b, 'p3' => $c));
4844
+ $id = $this->catalogId;
4845
+ $this->o_catalog($id, 'openHere', $this->numObj);
4846
+ }
4847
+
4848
+ /**
4849
+ * Add JavaScript code to the PDF document
4850
+ *
4851
+ * @param string $code
4852
+ * @return void
4853
+ */
4854
+ function addJavascript($code) {
4855
+ $this->javascript .= $code;
4856
+ }
4857
+
4858
+ /**
4859
+ * create a labelled destination within the document
4860
+ */
4861
+ function addDestination($label, $style, $a = 0, $b = 0, $c = 0) {
4862
+ // associates the given label with the destination, it is done this way so that a destination can be specified after
4863
+ // it has been linked to
4864
+ // styles are the same as the 'openHere' function
4865
+ $this->numObj++;
4866
+ $this->o_destination($this->numObj, 'new', array('page' => $this->currentPage, 'type' => $style, 'p1' => $a, 'p2' => $b, 'p3' => $c));
4867
+ $id = $this->numObj;
4868
+
4869
+ // store the label->idf relationship, note that this means that labels can be used only once
4870
+ $this->destinations["$label"] = $id;
4871
+ }
4872
+
4873
+ /**
4874
+ * define font families, this is used to initialize the font families for the default fonts
4875
+ * and for the user to add new ones for their fonts. The default bahavious can be overridden should
4876
+ * that be desired.
4877
+ */
4878
+ function setFontFamily($family, $options = '') {
4879
+ if (!is_array($options)) {
4880
+ if ($family === 'init') {
4881
+ // set the known family groups
4882
+ // these font families will be used to enable bold and italic markers to be included
4883
+ // within text streams. html forms will be used... <b></b> <i></i>
4884
+ $this->fontFamilies['Helvetica.afm'] =
4885
+ array('b' => 'Helvetica-Bold.afm',
4886
+ 'i' => 'Helvetica-Oblique.afm',
4887
+ 'bi' => 'Helvetica-BoldOblique.afm',
4888
+ 'ib' => 'Helvetica-BoldOblique.afm');
4889
+
4890
+ $this->fontFamilies['Courier.afm'] =
4891
+ array('b' => 'Courier-Bold.afm',
4892
+ 'i' => 'Courier-Oblique.afm',
4893
+ 'bi' => 'Courier-BoldOblique.afm',
4894
+ 'ib' => 'Courier-BoldOblique.afm');
4895
+
4896
+ $this->fontFamilies['Times-Roman.afm'] =
4897
+ array('b' => 'Times-Bold.afm',
4898
+ 'i' => 'Times-Italic.afm',
4899
+ 'bi' => 'Times-BoldItalic.afm',
4900
+ 'ib' => 'Times-BoldItalic.afm');
4901
+ }
4902
+ } else {
4903
+
4904
+ // the user is trying to set a font family
4905
+ // note that this can also be used to set the base ones to something else
4906
+ if (mb_strlen($family)) {
4907
+ $this->fontFamilies[$family] = $options;
4908
+ }
4909
+ }
4910
+ }
4911
+
4912
+ /**
4913
+ * used to add messages for use in debugging
4914
+ */
4915
+ function addMessage($message) {
4916
+ $this->messages.= $message."\n";
4917
+ }
4918
+
4919
+ /**
4920
+ * a few functions which should allow the document to be treated transactionally.
4921
+ */
4922
+ function transaction($action) {
4923
+ switch ($action) {
4924
+ case 'start':
4925
+ // store all the data away into the checkpoint variable
4926
+ $data = get_object_vars($this);
4927
+ $this->checkpoint = $data;
4928
+ unset($data);
4929
+ break;
4930
+
4931
+ case 'commit':
4932
+ if (is_array($this->checkpoint) && isset($this->checkpoint['checkpoint'])) {
4933
+ $tmp = $this->checkpoint['checkpoint'];
4934
+ $this->checkpoint = $tmp;
4935
+ unset($tmp);
4936
+ } else {
4937
+ $this->checkpoint = '';
4938
+ }
4939
+ break;
4940
+
4941
+ case 'rewind':
4942
+ // do not destroy the current checkpoint, but move us back to the state then, so that we can try again
4943
+ if (is_array($this->checkpoint)) {
4944
+ // can only abort if were inside a checkpoint
4945
+ $tmp = $this->checkpoint;
4946
+
4947
+ foreach ($tmp as $k => $v) {
4948
+ if ($k !== 'checkpoint') {
4949
+ $this->$k = $v;
4950
+ }
4951
+ }
4952
+ unset($tmp);
4953
+ }
4954
+ break;
4955
+
4956
+ case 'abort':
4957
+ if (is_array($this->checkpoint)) {
4958
+ // can only abort if were inside a checkpoint
4959
+ $tmp = $this->checkpoint;
4960
+ foreach ($tmp as $k => $v) {
4961
+ $this->$k = $v;
4962
+ }
4963
+ unset($tmp);
4964
+ }
4965
+ break;
4966
+ }
4967
+ }
4968
+ }
4969
+
dompdf/lib/fonts/Courier-Bold.afm ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ StartFontMetrics 4.1
2
+ Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
3
+ Comment Creation Date: Mon Jun 23 16:28:00 0:00:00
4
+ Comment UniqueID 43048
5
+ Comment VMusage 41139 52164
6
+ FontName Courier-Bold
7
+ FullName Courier Bold
8
+ FamilyName Courier
9
+ Weight Bold
10
+ ItalicAngle 0
11
+ IsFixedPitch true
12
+ CharacterSet ExtendedRoman
13
+ FontBBox -113 -250 749 801
14
+ UnderlinePosition -100
15
+ UnderlineThickness 50
16
+ Version 003.000
17
+ Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
18
+ EncodingScheme WinAnsiEncoding
19
+ CapHeight 562
20
+ XHeight 439
21
+ Ascender 629
22
+ Descender -157
23
+ StdHW 84
24
+ StdVW 106
25
+ StartCharMetrics 317
26
+ C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
27
+ C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
28
+ C 33 ; WX 600 ; N exclam ; B 202 -15 398 572 ;
29
+ C 34 ; WX 600 ; N quotedbl ; B 135 277 465 562 ;
30
+ C 35 ; WX 600 ; N numbersign ; B 56 -45 544 651 ;
31
+ C 36 ; WX 600 ; N dollar ; B 82 -126 519 666 ;
32
+ C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ;
33
+ C 38 ; WX 600 ; N ampersand ; B 36 -15 546 543 ;
34
+ C 146 ; WX 600 ; N quoteright ; B 171 277 423 562 ;
35
+ C 40 ; WX 600 ; N parenleft ; B 219 -102 461 616 ;
36
+ C 41 ; WX 600 ; N parenright ; B 139 -102 381 616 ;
37
+ C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ;
38
+ C 43 ; WX 600 ; N plus ; B 71 39 529 478 ;
39
+ C 44 ; WX 600 ; N comma ; B 123 -111 393 174 ;
40
+ C 45 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
41
+ C 173 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
42
+ C 46 ; WX 600 ; N period ; B 192 -15 408 171 ;
43
+ C 47 ; WX 600 ; N slash ; B 98 -77 502 626 ;
44
+ C 48 ; WX 600 ; N zero ; B 87 -15 513 616 ;
45
+ C 49 ; WX 600 ; N one ; B 81 0 539 616 ;
46
+ C 50 ; WX 600 ; N two ; B 61 0 499 616 ;
47
+ C 51 ; WX 600 ; N three ; B 63 -15 501 616 ;
48
+ C 52 ; WX 600 ; N four ; B 53 0 507 616 ;
49
+ C 53 ; WX 600 ; N five ; B 70 -15 521 601 ;
50
+ C 54 ; WX 600 ; N six ; B 90 -15 521 616 ;
51
+ C 55 ; WX 600 ; N seven ; B 55 0 494 601 ;
52
+ C 56 ; WX 600 ; N eight ; B 83 -15 517 616 ;
53
+ C 57 ; WX 600 ; N nine ; B 79 -15 510 616 ;
54
+ C 58 ; WX 600 ; N colon ; B 191 -15 407 425 ;
55
+ C 59 ; WX 600 ; N semicolon ; B 123 -111 408 425 ;
56
+ C 60 ; WX 600 ; N less ; B 66 15 523 501 ;
57
+ C 61 ; WX 600 ; N equal ; B 71 118 529 398 ;
58
+ C 62 ; WX 600 ; N greater ; B 77 15 534 501 ;
59
+ C 63 ; WX 600 ; N question ; B 98 -14 501 580 ;
60
+ C 64 ; WX 600 ; N at ; B 16 -15 584 616 ;
61
+ C 65 ; WX 600 ; N A ; B -9 0 609 562 ;
62
+ C 66 ; WX 600 ; N B ; B 30 0 573 562 ;
63
+ C 67 ; WX 600 ; N C ; B 22 -18 560 580 ;
64
+ C 68 ; WX 600 ; N D ; B 30 0 594 562 ;
65
+ C 69 ; WX 600 ; N E ; B 25 0 560 562 ;
66
+ C 70 ; WX 600 ; N F ; B 39 0 570 562 ;
67
+ C 71 ; WX 600 ; N G ; B 22 -18 594 580 ;
68
+ C 72 ; WX 600 ; N H ; B 20 0 580 562 ;
69
+ C 73 ; WX 600 ; N I ; B 77 0 523 562 ;
70
+ C 74 ; WX 600 ; N J ; B 37 -18 601 562 ;
71
+ C 75 ; WX 600 ; N K ; B 21 0 599 562 ;
72
+ C 76 ; WX 600 ; N L ; B 39 0 578 562 ;
73
+ C 77 ; WX 600 ; N M ; B -2 0 602 562 ;
74
+ C 78 ; WX 600 ; N N ; B 8 -12 610 562 ;
75
+ C 79 ; WX 600 ; N O ; B 22 -18 578 580 ;
76
+ C 80 ; WX 600 ; N P ; B 48 0 559 562 ;
77
+ C 81 ; WX 600 ; N Q ; B 32 -138 578 580 ;
78
+ C 82 ; WX 600 ; N R ; B 24 0 599 562 ;
79
+ C 83 ; WX 600 ; N S ; B 47 -22 553 582 ;
80
+ C 84 ; WX 600 ; N T ; B 21 0 579 562 ;
81
+ C 85 ; WX 600 ; N U ; B 4 -18 596 562 ;
82
+ C 86 ; WX 600 ; N V ; B -13 0 613 562 ;
83
+ C 87 ; WX 600 ; N W ; B -18 0 618 562 ;
84
+ C 88 ; WX 600 ; N X ; B 12 0 588 562 ;
85
+ C 89 ; WX 600 ; N Y ; B 12 0 589 562 ;
86
+ C 90 ; WX 600 ; N Z ; B 62 0 539 562 ;
87
+ C 91 ; WX 600 ; N bracketleft ; B 245 -102 475 616 ;
88
+ C 92 ; WX 600 ; N backslash ; B 99 -77 503 626 ;
89
+ C 93 ; WX 600 ; N bracketright ; B 125 -102 355 616 ;
90
+ C 94 ; WX 600 ; N asciicircum ; B 108 250 492 616 ;
91
+ C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
92
+ C 145 ; WX 600 ; N quoteleft ; B 178 277 428 562 ;
93
+ C 97 ; WX 600 ; N a ; B 35 -15 570 454 ;
94
+ C 98 ; WX 600 ; N b ; B 0 -15 584 626 ;
95
+ C 99 ; WX 600 ; N c ; B 40 -15 545 459 ;
96
+ C 100 ; WX 600 ; N d ; B 20 -15 591 626 ;
97
+ C 101 ; WX 600 ; N e ; B 40 -15 563 454 ;
98
+ C 102 ; WX 600 ; N f ; B 83 0 547 626 ; L i fi ; L l fl ;
99
+ C 103 ; WX 600 ; N g ; B 30 -146 580 454 ;
100
+ C 104 ; WX 600 ; N h ; B 5 0 592 626 ;
101
+ C 105 ; WX 600 ; N i ; B 77 0 523 658 ;
102
+ C 106 ; WX 600 ; N j ; B 63 -146 440 658 ;
103
+ C 107 ; WX 600 ; N k ; B 20 0 585 626 ;
104
+ C 108 ; WX 600 ; N l ; B 77 0 523 626 ;
105
+ C 109 ; WX 600 ; N m ; B -22 0 626 454 ;
106
+ C 110 ; WX 600 ; N n ; B 18 0 592 454 ;
107
+ C 111 ; WX 600 ; N o ; B 30 -15 570 454 ;
108
+ C 112 ; WX 600 ; N p ; B -1 -142 570 454 ;
109
+ C 113 ; WX 600 ; N q ; B 20 -142 591 454 ;
110
+ C 114 ; WX 600 ; N r ; B 47 0 580 454 ;
111
+ C 115 ; WX 600 ; N s ; B 68 -17 535 459 ;
112
+ C 116 ; WX 600 ; N t ; B 47 -15 532 562 ;
113
+ C 117 ; WX 600 ; N u ; B -1 -15 569 439 ;
114
+ C 118 ; WX 600 ; N v ; B -1 0 601 439 ;
115
+ C 119 ; WX 600 ; N w ; B -18 0 618 439 ;
116
+ C 120 ; WX 600 ; N x ; B 6 0 594 439 ;
117
+ C 121 ; WX 600 ; N y ; B -4 -142 601 439 ;
118
+ C 122 ; WX 600 ; N z ; B 81 0 520 439 ;
119
+ C 123 ; WX 600 ; N braceleft ; B 160 -102 464 616 ;
120
+ C 124 ; WX 600 ; N bar ; B 255 -250 345 750 ;
121
+ C 125 ; WX 600 ; N braceright ; B 136 -102 440 616 ;
122
+ C 126 ; WX 600 ; N asciitilde ; B 71 153 530 356 ;
123
+ C 161 ; WX 600 ; N exclamdown ; B 202 -146 398 449 ;
124
+ C 162 ; WX 600 ; N cent ; B 66 -49 518 614 ;
125
+ C 163 ; WX 600 ; N sterling ; B 72 -28 558 611 ;
126
+ C -1 ; WX 600 ; N fraction ; B 25 -60 576 661 ;
127
+ C 165 ; WX 600 ; N yen ; B 10 0 590 562 ;
128
+ C 131 ; WX 600 ; N florin ; B -30 -131 572 616 ;
129
+ C 167 ; WX 600 ; N section ; B 83 -70 517 580 ;
130
+ C 164 ; WX 600 ; N currency ; B 54 49 546 517 ;
131
+ C 39 ; WX 600 ; N quotesingle ; B 227 277 373 562 ;
132
+ C 147 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ;
133
+ C 170 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
134
+ C 139 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
135
+ C 155 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
136
+ C -1 ; WX 600 ; N fi ; B 12 0 593 626 ;
137
+ C -1 ; WX 600 ; N fl ; B 12 0 593 626 ;
138
+ C 150 ; WX 600 ; N endash ; B 65 203 535 313 ;
139
+ C 134 ; WX 600 ; N dagger ; B 106 -70 494 580 ;
140
+ C 135 ; WX 600 ; N daggerdbl ; B 106 -70 494 580 ;
141
+ C 183 ; WX 600 ; N periodcentered ; B 196 165 404 351 ;
142
+ C 182 ; WX 600 ; N paragraph ; B 6 -70 576 580 ;
143
+ C 149 ; WX 600 ; N bullet ; B 140 132 460 430 ;
144
+ C 130 ; WX 600 ; N quotesinglbase ; B 175 -142 427 143 ;
145
+ C 132 ; WX 600 ; N quotedblbase ; B 65 -142 529 143 ;
146
+ C 148 ; WX 600 ; N quotedblright ; B 61 277 525 562 ;
147
+ C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ;
148
+ C 133 ; WX 600 ; N ellipsis ; B 26 -15 574 116 ;
149
+ C 137 ; WX 600 ; N perthousand ; B -113 -15 713 616 ;
150
+ C 191 ; WX 600 ; N questiondown ; B 99 -146 502 449 ;
151
+ C 96 ; WX 600 ; N grave ; B 132 508 395 661 ;
152
+ C 180 ; WX 600 ; N acute ; B 205 508 468 661 ;
153
+ C 136 ; WX 600 ; N circumflex ; B 103 483 497 657 ;
154
+ C 152 ; WX 600 ; N tilde ; B 89 493 512 636 ;
155
+ C 175 ; WX 600 ; N macron ; B 88 505 512 585 ;
156
+ C -1 ; WX 600 ; N breve ; B 83 468 517 631 ;
157
+ C -1 ; WX 600 ; N dotaccent ; B 230 498 370 638 ;
158
+ C 168 ; WX 600 ; N dieresis ; B 128 498 472 638 ;
159
+ C -1 ; WX 600 ; N ring ; B 198 481 402 678 ;
160
+ C 184 ; WX 600 ; N cedilla ; B 205 -206 387 0 ;
161
+ C -1 ; WX 600 ; N hungarumlaut ; B 68 488 588 661 ;
162
+ C -1 ; WX 600 ; N ogonek ; B 169 -199 400 0 ;
163
+ C -1 ; WX 600 ; N caron ; B 103 493 497 667 ;
164
+ C 151 ; WX 600 ; N emdash ; B -10 203 610 313 ;
165
+ C 198 ; WX 600 ; N AE ; B -29 0 602 562 ;
166
+ C 170 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ;
167
+ C -1 ; WX 600 ; N Lslash ; B 39 0 578 562 ;
168
+ C 216 ; WX 600 ; N Oslash ; B 22 -22 578 584 ;
169
+ C 140 ; WX 600 ; N OE ; B -25 0 595 562 ;
170
+ C 186 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ;
171
+ C 230 ; WX 600 ; N ae ; B -4 -15 601 454 ;
172
+ C -1 ; WX 600 ; N dotlessi ; B 77 0 523 439 ;
173
+ C -1 ; WX 600 ; N lslash ; B 77 0 523 626 ;
174
+ C 248 ; WX 600 ; N oslash ; B 30 -24 570 463 ;
175
+ C 156 ; WX 600 ; N oe ; B -18 -15 611 454 ;
176
+ C 223 ; WX 600 ; N germandbls ; B 22 -15 596 626 ;
177
+ C 207 ; WX 600 ; N Idieresis ; B 77 0 523 761 ;
178
+ C 233 ; WX 600 ; N eacute ; B 40 -15 563 661 ;
179
+ C -1 ; WX 600 ; N abreve ; B 35 -15 570 661 ;
180
+ C -1 ; WX 600 ; N uhungarumlaut ; B -1 -15 628 661 ;
181
+ C -1 ; WX 600 ; N ecaron ; B 40 -15 563 667 ;
182
+ C 159 ; WX 600 ; N Ydieresis ; B 12 0 589 761 ;
183
+ C 247 ; WX 600 ; N divide ; B 71 16 529 500 ;
184
+ C 221 ; WX 600 ; N Yacute ; B 12 0 589 784 ;
185
+ C 194 ; WX 600 ; N Acircumflex ; B -9 0 609 780 ;
186
+ C 225 ; WX 600 ; N aacute ; B 35 -15 570 661 ;
187
+ C 219 ; WX 600 ; N Ucircumflex ; B 4 -18 596 780 ;
188
+ C 253 ; WX 600 ; N yacute ; B -4 -142 601 661 ;
189
+ C -1 ; WX 600 ; N scommaaccent ; B 68 -250 535 459 ;
190
+ C 234 ; WX 600 ; N ecircumflex ; B 40 -15 563 657 ;
191
+ C -1 ; WX 600 ; N Uring ; B 4 -18 596 801 ;
192
+ C 220 ; WX 600 ; N Udieresis ; B 4 -18 596 761 ;
193
+ C -1 ; WX 600 ; N aogonek ; B 35 -199 586 454 ;
194
+ C 218 ; WX 600 ; N Uacute ; B 4 -18 596 784 ;
195
+ C -1 ; WX 600 ; N uogonek ; B -1 -199 585 439 ;
196
+ C 203 ; WX 600 ; N Edieresis ; B 25 0 560 761 ;
197
+ C -1 ; WX 600 ; N Dcroat ; B 30 0 594 562 ;
198
+ C -1 ; WX 600 ; N commaaccent ; B 205 -250 397 -57 ;
199
+ C 169 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
200
+ C -1 ; WX 600 ; N Emacron ; B 25 0 560 708 ;
201
+ C -1 ; WX 600 ; N ccaron ; B 40 -15 545 667 ;
202
+ C 229 ; WX 600 ; N aring ; B 35 -15 570 678 ;
203
+ C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 610 562 ;
204
+ C -1 ; WX 600 ; N lacute ; B 77 0 523 801 ;
205
+ C 224 ; WX 600 ; N agrave ; B 35 -15 570 661 ;
206
+ C -1 ; WX 600 ; N Tcommaaccent ; B 21 -250 579 562 ;
207
+ C -1 ; WX 600 ; N Cacute ; B 22 -18 560 784 ;
208
+ C 227 ; WX 600 ; N atilde ; B 35 -15 570 636 ;
209
+ C -1 ; WX 600 ; N Edotaccent ; B 25 0 560 761 ;
210
+ C 154 ; WX 600 ; N scaron ; B 68 -17 535 667 ;
211
+ C -1 ; WX 600 ; N scedilla ; B 68 -206 535 459 ;
212
+ C 237 ; WX 600 ; N iacute ; B 77 0 523 661 ;
213
+ C -1 ; WX 600 ; N lozenge ; B 66 0 534 740 ;
214
+ C -1 ; WX 600 ; N Rcaron ; B 24 0 599 790 ;
215
+ C -1 ; WX 600 ; N Gcommaaccent ; B 22 -250 594 580 ;
216
+ C 251 ; WX 600 ; N ucircumflex ; B -1 -15 569 657 ;
217
+ C 226 ; WX 600 ; N acircumflex ; B 35 -15 570 657 ;
218
+ C -1 ; WX 600 ; N Amacron ; B -9 0 609 708 ;
219
+ C -1 ; WX 600 ; N rcaron ; B 47 0 580 667 ;
220
+ C 231 ; WX 600 ; N ccedilla ; B 40 -206 545 459 ;
221
+ C -1 ; WX 600 ; N Zdotaccent ; B 62 0 539 761 ;
222
+ C 222 ; WX 600 ; N Thorn ; B 48 0 557 562 ;
223
+ C -1 ; WX 600 ; N Omacron ; B 22 -18 578 708 ;
224
+ C -1 ; WX 600 ; N Racute ; B 24 0 599 784 ;
225
+ C -1 ; WX 600 ; N Sacute ; B 47 -22 553 784 ;
226
+ C -1 ; WX 600 ; N dcaron ; B 20 -15 727 626 ;
227
+ C -1 ; WX 600 ; N Umacron ; B 4 -18 596 708 ;
228
+ C -1 ; WX 600 ; N uring ; B -1 -15 569 678 ;
229
+ C 179 ; WX 600 ; N threesuperior ; B 138 222 433 616 ;
230
+ C 210 ; WX 600 ; N Ograve ; B 22 -18 578 784 ;
231
+ C 192 ; WX 600 ; N Agrave ; B -9 0 609 784 ;
232
+ C -1 ; WX 600 ; N Abreve ; B -9 0 609 784 ;
233
+ C 215 ; WX 600 ; N multiply ; B 81 39 520 478 ;
234
+ C 250 ; WX 600 ; N uacute ; B -1 -15 569 661 ;
235
+ C -1 ; WX 600 ; N Tcaron ; B 21 0 579 790 ;
236
+ C -1 ; WX 600 ; N partialdiff ; B 63 -38 537 728 ;
237
+ C 255 ; WX 600 ; N ydieresis ; B -4 -142 601 638 ;
238
+ C -1 ; WX 600 ; N Nacute ; B 8 -12 610 784 ;
239
+ C 238 ; WX 600 ; N icircumflex ; B 73 0 523 657 ;
240
+ C 202 ; WX 600 ; N Ecircumflex ; B 25 0 560 780 ;
241
+ C 228 ; WX 600 ; N adieresis ; B 35 -15 570 638 ;
242
+ C 235 ; WX 600 ; N edieresis ; B 40 -15 563 638 ;
243
+ C -1 ; WX 600 ; N cacute ; B 40 -15 545 661 ;
244
+ C -1 ; WX 600 ; N nacute ; B 18 0 592 661 ;
245
+ C -1 ; WX 600 ; N umacron ; B -1 -15 569 585 ;
246
+ C -1 ; WX 600 ; N Ncaron ; B 8 -12 610 790 ;
247
+ C 205 ; WX 600 ; N Iacute ; B 77 0 523 784 ;
248
+ C 177 ; WX 600 ; N plusminus ; B 71 24 529 515 ;
249
+ C 166 ; WX 600 ; N brokenbar ; B 255 -175 345 675 ;
250
+ C 174 ; WX 600 ; N registered ; B 0 -18 600 580 ;
251
+ C -1 ; WX 600 ; N Gbreve ; B 22 -18 594 784 ;
252
+ C -1 ; WX 600 ; N Idotaccent ; B 77 0 523 761 ;
253
+ C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ;
254
+ C 200 ; WX 600 ; N Egrave ; B 25 0 560 784 ;
255
+ C -1 ; WX 600 ; N racute ; B 47 0 580 661 ;
256
+ C -1 ; WX 600 ; N omacron ; B 30 -15 570 585 ;
257
+ C -1 ; WX 600 ; N Zacute ; B 62 0 539 784 ;
258
+ C 142 ; WX 600 ; N Zcaron ; B 62 0 539 790 ;
259
+ C -1 ; WX 600 ; N greaterequal ; B 26 0 523 696 ;
260
+ C 208 ; WX 600 ; N Eth ; B 30 0 594 562 ;
261
+ C 199 ; WX 600 ; N Ccedilla ; B 22 -206 560 580 ;
262
+ C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 523 626 ;
263
+ C -1 ; WX 600 ; N tcaron ; B 47 -15 532 703 ;
264
+ C -1 ; WX 600 ; N eogonek ; B 40 -199 563 454 ;
265
+ C -1 ; WX 600 ; N Uogonek ; B 4 -199 596 562 ;
266
+ C 193 ; WX 600 ; N Aacute ; B -9 0 609 784 ;
267
+ C 196 ; WX 600 ; N Adieresis ; B -9 0 609 761 ;
268
+ C 232 ; WX 600 ; N egrave ; B 40 -15 563 661 ;
269
+ C -1 ; WX 600 ; N zacute ; B 81 0 520 661 ;
270
+ C -1 ; WX 600 ; N iogonek ; B 77 -199 523 658 ;
271
+ C 211 ; WX 600 ; N Oacute ; B 22 -18 578 784 ;
272
+ C 243 ; WX 600 ; N oacute ; B 30 -15 570 661 ;
273
+ C -1 ; WX 600 ; N amacron ; B 35 -15 570 585 ;
274
+ C -1 ; WX 600 ; N sacute ; B 68 -17 535 661 ;
275
+ C 239 ; WX 600 ; N idieresis ; B 77 0 523 618 ;
276
+ C 212 ; WX 600 ; N Ocircumflex ; B 22 -18 578 780 ;
277
+ C 217 ; WX 600 ; N Ugrave ; B 4 -18 596 784 ;
278
+ C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
279
+ C 254 ; WX 600 ; N thorn ; B -14 -142 570 626 ;
280
+ C 178 ; WX 600 ; N twosuperior ; B 143 230 436 616 ;
281
+ C 214 ; WX 600 ; N Odieresis ; B 22 -18 578 761 ;
282
+ C 181 ; WX 600 ; N mu ; B -1 -142 569 439 ;
283
+ C 236 ; WX 600 ; N igrave ; B 77 0 523 661 ;
284
+ C -1 ; WX 600 ; N ohungarumlaut ; B 30 -15 668 661 ;
285
+ C -1 ; WX 600 ; N Eogonek ; B 25 -199 576 562 ;
286
+ C -1 ; WX 600 ; N dcroat ; B 20 -15 591 626 ;
287
+ C 190 ; WX 600 ; N threequarters ; B -47 -60 648 661 ;
288
+ C -1 ; WX 600 ; N Scedilla ; B 47 -206 553 582 ;
289
+ C -1 ; WX 600 ; N lcaron ; B 77 0 597 626 ;
290
+ C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 599 562 ;
291
+ C -1 ; WX 600 ; N Lacute ; B 39 0 578 784 ;
292
+ C 153 ; WX 600 ; N trademark ; B -9 230 749 562 ;
293
+ C -1 ; WX 600 ; N edotaccent ; B 40 -15 563 638 ;
294
+ C 204 ; WX 600 ; N Igrave ; B 77 0 523 784 ;
295
+ C -1 ; WX 600 ; N Imacron ; B 77 0 523 708 ;
296
+ C -1 ; WX 600 ; N Lcaron ; B 39 0 637 562 ;
297
+ C 189 ; WX 600 ; N onehalf ; B -47 -60 648 661 ;
298
+ C -1 ; WX 600 ; N lessequal ; B 26 0 523 696 ;
299
+ C 244 ; WX 600 ; N ocircumflex ; B 30 -15 570 657 ;
300
+ C 241 ; WX 600 ; N ntilde ; B 18 0 592 636 ;
301
+ C -1 ; WX 600 ; N Uhungarumlaut ; B 4 -18 638 784 ;
302
+ C 201 ; WX 600 ; N Eacute ; B 25 0 560 784 ;
303
+ C -1 ; WX 600 ; N emacron ; B 40 -15 563 585 ;
304
+ C -1 ; WX 600 ; N gbreve ; B 30 -146 580 661 ;
305
+ C 188 ; WX 600 ; N onequarter ; B -56 -60 656 661 ;
306
+ C 138 ; WX 600 ; N Scaron ; B 47 -22 553 790 ;
307
+ C -1 ; WX 600 ; N Scommaaccent ; B 47 -250 553 582 ;
308
+ C -1 ; WX 600 ; N Ohungarumlaut ; B 22 -18 628 784 ;
309
+ C 176 ; WX 600 ; N degree ; B 86 243 474 616 ;
310
+ C 242 ; WX 600 ; N ograve ; B 30 -15 570 661 ;
311
+ C -1 ; WX 600 ; N Ccaron ; B 22 -18 560 790 ;
312
+ C 249 ; WX 600 ; N ugrave ; B -1 -15 569 661 ;
313
+ C -1 ; WX 600 ; N radical ; B -19 -104 473 778 ;
314
+ C -1 ; WX 600 ; N Dcaron ; B 30 0 594 790 ;
315
+ C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 580 454 ;
316
+ C 209 ; WX 600 ; N Ntilde ; B 8 -12 610 759 ;
317
+ C 245 ; WX 600 ; N otilde ; B 30 -15 570 636 ;
318
+ C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 599 562 ;
319
+ C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 578 562 ;
320
+ C 195 ; WX 600 ; N Atilde ; B -9 0 609 759 ;
321
+ C -1 ; WX 600 ; N Aogonek ; B -9 -199 625 562 ;
322
+ C 197 ; WX 600 ; N Aring ; B -9 0 609 801 ;
323
+ C 213 ; WX 600 ; N Otilde ; B 22 -18 578 759 ;
324
+ C -1 ; WX 600 ; N zdotaccent ; B 81 0 520 638 ;
325
+ C -1 ; WX 600 ; N Ecaron ; B 25 0 560 790 ;
326
+ C -1 ; WX 600 ; N Iogonek ; B 77 -199 523 562 ;
327
+ C -1 ; WX 600 ; N kcommaaccent ; B 20 -250 585 626 ;
328
+ C -1 ; WX 600 ; N minus ; B 71 203 529 313 ;
329
+ C 206 ; WX 600 ; N Icircumflex ; B 77 0 523 780 ;
330
+ C -1 ; WX 600 ; N ncaron ; B 18 0 592 667 ;
331
+ C -1 ; WX 600 ; N tcommaaccent ; B 47 -250 532 562 ;
332
+ C 172 ; WX 600 ; N logicalnot ; B 71 103 529 413 ;
333
+ C 246 ; WX 600 ; N odieresis ; B 30 -15 570 638 ;
334
+ C 252 ; WX 600 ; N udieresis ; B -1 -15 569 638 ;
335
+ C -1 ; WX 600 ; N notequal ; B 12 -47 537 563 ;
336
+ C -1 ; WX 600 ; N gcommaaccent ; B 30 -146 580 714 ;
337
+ C 240 ; WX 600 ; N eth ; B 58 -27 543 626 ;
338
+ C 158 ; WX 600 ; N zcaron ; B 81 0 520 667 ;
339
+ C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 592 454 ;
340
+ C 185 ; WX 600 ; N onesuperior ; B 153 230 447 616 ;
341
+ C -1 ; WX 600 ; N imacron ; B 77 0 523 585 ;
342
+ C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
343
+ EndCharMetrics
344
+ EndFontMetrics
dompdf/lib/fonts/Courier-BoldOblique.afm ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ StartFontMetrics 4.1
2
+ Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
3
+ Comment Creation Date: Mon Jun 23 16:28:46 0:00:00
4
+ Comment UniqueID 43049
5
+ Comment VMusage 17529 79244
6
+ FontName Courier-BoldOblique
7
+ FullName Courier Bold Oblique
8
+ FamilyName Courier
9
+ Weight Bold
10
+ ItalicAngle -12
11
+ IsFixedPitch true
12
+ CharacterSet ExtendedRoman
13
+ FontBBox -57 -250 869 801
14
+ UnderlinePosition -100
15
+ UnderlineThickness 50
16
+ Version 3
17
+ Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
18
+ EncodingScheme WinAnsiEncoding
19
+ CapHeight 562
20
+ XHeight 439
21
+ Ascender 629
22
+ Descender -157
23
+ StdHW 84
24
+ StdVW 106
25
+ StartCharMetrics 317
26
+ C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
27
+ C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
28
+ C 33 ; WX 600 ; N exclam ; B 215 -15 495 572 ;
29
+ C 34 ; WX 600 ; N quotedbl ; B 211 277 585 562 ;
30
+ C 35 ; WX 600 ; N numbersign ; B 88 -45 641 651 ;
31
+ C 36 ; WX 600 ; N dollar ; B 87 -126 630 666 ;
32
+ C 37 ; WX 600 ; N percent ; B 101 -15 625 616 ;
33
+ C 38 ; WX 600 ; N ampersand ; B 61 -15 595 543 ;
34
+ C 146 ; WX 600 ; N quoteright ; B 229 277 543 562 ;
35
+ C 40 ; WX 600 ; N parenleft ; B 265 -102 592 616 ;
36
+ C 41 ; WX 600 ; N parenright ; B 117 -102 444 616 ;
37
+ C 42 ; WX 600 ; N asterisk ; B 179 219 598 601 ;
38
+ C 43 ; WX 600 ; N plus ; B 114 39 596 478 ;
39
+ C 44 ; WX 600 ; N comma ; B 99 -111 430 174 ;
40
+ C 45 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
41
+ C 173 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
42
+ C 46 ; WX 600 ; N period ; B 206 -15 427 171 ;
43
+ C 47 ; WX 600 ; N slash ; B 90 -77 626 626 ;
44
+ C 48 ; WX 600 ; N zero ; B 135 -15 593 616 ;
45
+ C 49 ; WX 600 ; N one ; B 93 0 562 616 ;
46
+ C 50 ; WX 600 ; N two ; B 61 0 594 616 ;
47
+ C 51 ; WX 600 ; N three ; B 71 -15 571 616 ;
48
+ C 52 ; WX 600 ; N four ; B 81 0 559 616 ;
49
+ C 53 ; WX 600 ; N five ; B 77 -15 621 601 ;
50
+ C 54 ; WX 600 ; N six ; B 135 -15 652 616 ;
51
+ C 55 ; WX 600 ; N seven ; B 147 0 622 601 ;
52
+ C 56 ; WX 600 ; N eight ; B 115 -15 604 616 ;
53
+ C 57 ; WX 600 ; N nine ; B 75 -15 592 616 ;
54
+ C 58 ; WX 600 ; N colon ; B 205 -15 480 425 ;
55
+ C 59 ; WX 600 ; N semicolon ; B 99 -111 481 425 ;
56
+ C 60 ; WX 600 ; N less ; B 120 15 613 501 ;
57
+ C 61 ; WX 600 ; N equal ; B 96 118 614 398 ;
58
+ C 62 ; WX 600 ; N greater ; B 97 15 589 501 ;
59
+ C 63 ; WX 600 ; N question ; B 183 -14 592 580 ;
60
+ C 64 ; WX 600 ; N at ; B 65 -15 642 616 ;
61
+ C 65 ; WX 600 ; N A ; B -9 0 632 562 ;
62
+ C 66 ; WX 600 ; N B ; B 30 0 630 562 ;
63
+ C 67 ; WX 600 ; N C ; B 74 -18 675 580 ;
64
+ C 68 ; WX 600 ; N D ; B 30 0 664 562 ;
65
+ C 69 ; WX 600 ; N E ; B 25 0 670 562 ;
66
+ C 70 ; WX 600 ; N F ; B 39 0 684 562 ;
67
+ C 71 ; WX 600 ; N G ; B 74 -18 675 580 ;
68
+ C 72 ; WX 600 ; N H ; B 20 0 700 562 ;
69
+ C 73 ; WX 600 ; N I ; B 77 0 643 562 ;
70
+ C 74 ; WX 600 ; N J ; B 58 -18 721 562 ;
71
+ C 75 ; WX 600 ; N K ; B 21 0 692 562 ;
72
+ C 76 ; WX 600 ; N L ; B 39 0 636 562 ;
73
+ C 77 ; WX 600 ; N M ; B -2 0 722 562 ;
74
+ C 78 ; WX 600 ; N N ; B 8 -12 730 562 ;
75
+ C 79 ; WX 600 ; N O ; B 74 -18 645 580 ;
76
+ C 80 ; WX 600 ; N P ; B 48 0 643 562 ;
77
+ C 81 ; WX 600 ; N Q ; B 83 -138 636 580 ;
78
+ C 82 ; WX 600 ; N R ; B 24 0 617 562 ;
79
+ C 83 ; WX 600 ; N S ; B 54 -22 673 582 ;
80
+ C 84 ; WX 600 ; N T ; B 86 0 679 562 ;
81
+ C 85 ; WX 600 ; N U ; B 101 -18 716 562 ;
82
+ C 86 ; WX 600 ; N V ; B 84 0 733 562 ;
83
+ C 87 ; WX 600 ; N W ; B 79 0 738 562 ;
84
+ C 88 ; WX 600 ; N X ; B 12 0 690 562 ;
85
+ C 89 ; WX 600 ; N Y ; B 109 0 709 562 ;
86
+ C 90 ; WX 600 ; N Z ; B 62 0 637 562 ;
87
+ C 91 ; WX 600 ; N bracketleft ; B 223 -102 606 616 ;
88
+ C 92 ; WX 600 ; N backslash ; B 222 -77 496 626 ;
89
+ C 93 ; WX 600 ; N bracketright ; B 103 -102 486 616 ;
90
+ C 94 ; WX 600 ; N asciicircum ; B 171 250 556 616 ;
91
+ C 95 ; WX 600 ; N underscore ; B -27 -125 585 -75 ;
92
+ C 145 ; WX 600 ; N quoteleft ; B 297 277 487 562 ;
93
+ C 97 ; WX 600 ; N a ; B 61 -15 593 454 ;
94
+ C 98 ; WX 600 ; N b ; B 13 -15 636 626 ;
95
+ C 99 ; WX 600 ; N c ; B 81 -15 631 459 ;
96
+ C 100 ; WX 600 ; N d ; B 60 -15 645 626 ;
97
+ C 101 ; WX 600 ; N e ; B 81 -15 605 454 ;
98
+ C 102 ; WX 600 ; N f ; B 83 0 677 626 ; L i fi ; L l fl ;
99
+ C 103 ; WX 600 ; N g ; B 40 -146 674 454 ;
100
+ C 104 ; WX 600 ; N h ; B 18 0 615 626 ;
101
+ C 105 ; WX 600 ; N i ; B 77 0 546 658 ;
102
+ C 106 ; WX 600 ; N j ; B 36 -146 580 658 ;
103
+ C 107 ; WX 600 ; N k ; B 33 0 643 626 ;
104
+ C 108 ; WX 600 ; N l ; B 77 0 546 626 ;
105
+ C 109 ; WX 600 ; N m ; B -22 0 649 454 ;
106
+ C 110 ; WX 600 ; N n ; B 18 0 615 454 ;
107
+ C 111 ; WX 600 ; N o ; B 71 -15 622 454 ;
108
+ C 112 ; WX 600 ; N p ; B -32 -142 622 454 ;
109
+ C 113 ; WX 600 ; N q ; B 60 -142 685 454 ;
110
+ C 114 ; WX 600 ; N r ; B 47 0 655 454 ;
111
+ C 115 ; WX 600 ; N s ; B 66 -17 608 459 ;
112
+ C 116 ; WX 600 ; N t ; B 118 -15 567 562 ;
113
+ C 117 ; WX 600 ; N u ; B 70 -15 592 439 ;
114
+ C 118 ; WX 600 ; N v ; B 70 0 695 439 ;
115
+ C 119 ; WX 600 ; N w ; B 53 0 712 439 ;
116
+ C 120 ; WX 600 ; N x ; B 6 0 671 439 ;
117
+ C 121 ; WX 600 ; N y ; B -21 -142 695 439 ;
118
+ C 122 ; WX 600 ; N z ; B 81 0 614 439 ;
119
+ C 123 ; WX 600 ; N braceleft ; B 203 -102 595 616 ;
120
+ C 124 ; WX 600 ; N bar ; B 201 -250 505 750 ;
121
+ C 125 ; WX 600 ; N braceright ; B 114 -102 506 616 ;
122
+ C 126 ; WX 600 ; N asciitilde ; B 120 153 590 356 ;
123
+ C 161 ; WX 600 ; N exclamdown ; B 196 -146 477 449 ;
124
+ C 162 ; WX 600 ; N cent ; B 121 -49 605 614 ;
125
+ C 163 ; WX 600 ; N sterling ; B 106 -28 650 611 ;
126
+ C -1 ; WX 600 ; N fraction ; B 22 -60 708 661 ;
127
+ C 165 ; WX 600 ; N yen ; B 98 0 710 562 ;
128
+ C 131 ; WX 600 ; N florin ; B -57 -131 702 616 ;
129
+ C 167 ; WX 600 ; N section ; B 74 -70 620 580 ;
130
+ C 164 ; WX 600 ; N currency ; B 77 49 644 517 ;
131
+ C 39 ; WX 600 ; N quotesingle ; B 303 277 493 562 ;
132
+ C 147 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ;
133
+ C 170 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ;
134
+ C 139 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ;
135
+ C 155 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ;
136
+ C -1 ; WX 600 ; N fi ; B 12 0 644 626 ;
137
+ C -1 ; WX 600 ; N fl ; B 12 0 644 626 ;
138
+ C 150 ; WX 600 ; N endash ; B 108 203 602 313 ;
139
+ C 134 ; WX 600 ; N dagger ; B 175 -70 586 580 ;
140
+ C 135 ; WX 600 ; N daggerdbl ; B 121 -70 587 580 ;
141
+ C 183 ; WX 600 ; N periodcentered ; B 248 165 461 351 ;
142
+ C 182 ; WX 600 ; N paragraph ; B 61 -70 700 580 ;
143
+ C 149 ; WX 600 ; N bullet ; B 196 132 523 430 ;
144
+ C 130 ; WX 600 ; N quotesinglbase ; B 144 -142 458 143 ;
145
+ C 132 ; WX 600 ; N quotedblbase ; B 34 -142 560 143 ;
146
+ C 148 ; WX 600 ; N quotedblright ; B 119 277 645 562 ;
147
+ C 187 ; WX 600 ; N guillemotright ; B 71 70 647 446 ;
148
+ C 133 ; WX 600 ; N ellipsis ; B 35 -15 587 116 ;
149
+ C 137 ; WX 600 ; N perthousand ; B -45 -15 743 616 ;
150
+ C 191 ; WX 600 ; N questiondown ; B 100 -146 509 449 ;
151
+ C 96 ; WX 600 ; N grave ; B 272 508 503 661 ;
152
+ C 180 ; WX 600 ; N acute ; B 312 508 609 661 ;
153
+ C 136 ; WX 600 ; N circumflex ; B 212 483 607 657 ;
154
+ C 152 ; WX 600 ; N tilde ; B 199 493 643 636 ;
155
+ C 175 ; WX 600 ; N macron ; B 195 505 637 585 ;
156
+ C -1 ; WX 600 ; N breve ; B 217 468 652 631 ;
157
+ C -1 ; WX 600 ; N dotaccent ; B 348 498 493 638 ;
158
+ C 168 ; WX 600 ; N dieresis ; B 246 498 595 638 ;
159
+ C -1 ; WX 600 ; N ring ; B 319 481 528 678 ;
160
+ C 184 ; WX 600 ; N cedilla ; B 168 -206 368 0 ;
161
+ C -1 ; WX 600 ; N hungarumlaut ; B 171 488 729 661 ;
162
+ C -1 ; WX 600 ; N ogonek ; B 143 -199 367 0 ;
163
+ C -1 ; WX 600 ; N caron ; B 238 493 633 667 ;
164
+ C 151 ; WX 600 ; N emdash ; B 33 203 677 313 ;
165
+ C 198 ; WX 600 ; N AE ; B -29 0 708 562 ;
166
+ C 170 ; WX 600 ; N ordfeminine ; B 188 196 526 580 ;
167
+ C -1 ; WX 600 ; N Lslash ; B 39 0 636 562 ;
168
+ C 216 ; WX 600 ; N Oslash ; B 48 -22 673 584 ;
169
+ C 140 ; WX 600 ; N OE ; B 26 0 701 562 ;
170
+ C 186 ; WX 600 ; N ordmasculine ; B 188 196 543 580 ;
171
+ C 230 ; WX 600 ; N ae ; B 21 -15 652 454 ;
172
+ C -1 ; WX 600 ; N dotlessi ; B 77 0 546 439 ;
173
+ C -1 ; WX 600 ; N lslash ; B 77 0 587 626 ;
174
+ C 248 ; WX 600 ; N oslash ; B 54 -24 638 463 ;
175
+ C 156 ; WX 600 ; N oe ; B 18 -15 662 454 ;
176
+ C 223 ; WX 600 ; N germandbls ; B 22 -15 629 626 ;
177
+ C 207 ; WX 600 ; N Idieresis ; B 77 0 643 761 ;
178
+ C 233 ; WX 600 ; N eacute ; B 81 -15 609 661 ;
179
+ C -1 ; WX 600 ; N abreve ; B 61 -15 658 661 ;
180
+ C -1 ; WX 600 ; N uhungarumlaut ; B 70 -15 769 661 ;
181
+ C -1 ; WX 600 ; N ecaron ; B 81 -15 633 667 ;
182
+ C 159 ; WX 600 ; N Ydieresis ; B 109 0 709 761 ;
183
+ C 247 ; WX 600 ; N divide ; B 114 16 596 500 ;
184
+ C 221 ; WX 600 ; N Yacute ; B 109 0 709 784 ;
185
+ C 194 ; WX 600 ; N Acircumflex ; B -9 0 632 780 ;
186
+ C 225 ; WX 600 ; N aacute ; B 61 -15 609 661 ;
187
+ C 219 ; WX 600 ; N Ucircumflex ; B 101 -18 716 780 ;
188
+ C 253 ; WX 600 ; N yacute ; B -21 -142 695 661 ;
189
+ C -1 ; WX 600 ; N scommaaccent ; B 66 -250 608 459 ;
190
+ C 234 ; WX 600 ; N ecircumflex ; B 81 -15 607 657 ;
191
+ C -1 ; WX 600 ; N Uring ; B 101 -18 716 801 ;
192
+ C 220 ; WX 600 ; N Udieresis ; B 101 -18 716 761 ;
193
+ C -1 ; WX 600 ; N aogonek ; B 61 -199 593 454 ;
194
+ C 218 ; WX 600 ; N Uacute ; B 101 -18 716 784 ;
195
+ C -1 ; WX 600 ; N uogonek ; B 70 -199 592 439 ;
196
+ C 203 ; WX 600 ; N Edieresis ; B 25 0 670 761 ;
197
+ C -1 ; WX 600 ; N Dcroat ; B 30 0 664 562 ;
198
+ C -1 ; WX 600 ; N commaaccent ; B 151 -250 385 -57 ;
199
+ C 169 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
200
+ C -1 ; WX 600 ; N Emacron ; B 25 0 670 708 ;
201
+ C -1 ; WX 600 ; N ccaron ; B 81 -15 633 667 ;
202
+ C 229 ; WX 600 ; N aring ; B 61 -15 593 678 ;
203
+ C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 730 562 ;
204
+ C -1 ; WX 600 ; N lacute ; B 77 0 639 801 ;
205
+ C 224 ; WX 600 ; N agrave ; B 61 -15 593 661 ;
206
+ C -1 ; WX 600 ; N Tcommaaccent ; B 86 -250 679 562 ;
207
+ C -1 ; WX 600 ; N Cacute ; B 74 -18 675 784 ;
208
+ C 227 ; WX 600 ; N atilde ; B 61 -15 643 636 ;
209
+ C -1 ; WX 600 ; N Edotaccent ; B 25 0 670 761 ;
210
+ C 154 ; WX 600 ; N scaron ; B 66 -17 633 667 ;
211
+ C -1 ; WX 600 ; N scedilla ; B 66 -206 608 459 ;
212
+ C 237 ; WX 600 ; N iacute ; B 77 0 609 661 ;
213
+ C -1 ; WX 600 ; N lozenge ; B 145 0 614 740 ;
214
+ C -1 ; WX 600 ; N Rcaron ; B 24 0 659 790 ;
215
+ C -1 ; WX 600 ; N Gcommaaccent ; B 74 -250 675 580 ;
216
+ C 251 ; WX 600 ; N ucircumflex ; B 70 -15 597 657 ;
217
+ C 226 ; WX 600 ; N acircumflex ; B 61 -15 607 657 ;
218
+ C -1 ; WX 600 ; N Amacron ; B -9 0 633 708 ;
219
+ C -1 ; WX 600 ; N rcaron ; B 47 0 655 667 ;
220
+ C 231 ; WX 600 ; N ccedilla ; B 81 -206 631 459 ;
221
+ C -1 ; WX 600 ; N Zdotaccent ; B 62 0 637 761 ;
222
+ C 222 ; WX 600 ; N Thorn ; B 48 0 620 562 ;
223
+ C -1 ; WX 600 ; N Omacron ; B 74 -18 663 708 ;
224
+ C -1 ; WX 600 ; N Racute ; B 24 0 665 784 ;
225
+ C -1 ; WX 600 ; N Sacute ; B 54 -22 673 784 ;
226
+ C -1 ; WX 600 ; N dcaron ; B 60 -15 861 626 ;
227
+ C -1 ; WX 600 ; N Umacron ; B 101 -18 716 708 ;
228
+ C -1 ; WX 600 ; N uring ; B 70 -15 592 678 ;
229
+ C 179 ; WX 600 ; N threesuperior ; B 193 222 526 616 ;
230
+ C 210 ; WX 600 ; N Ograve ; B 74 -18 645 784 ;
231
+ C 192 ; WX 600 ; N Agrave ; B -9 0 632 784 ;
232
+ C -1 ; WX 600 ; N Abreve ; B -9 0 684 784 ;
233
+ C 215 ; WX 600 ; N multiply ; B 104 39 606 478 ;
234
+ C 250 ; WX 600 ; N uacute ; B 70 -15 599 661 ;
235
+ C -1 ; WX 600 ; N Tcaron ; B 86 0 679 790 ;
236
+ C -1 ; WX 600 ; N partialdiff ; B 91 -38 627 728 ;
237
+ C 255 ; WX 600 ; N ydieresis ; B -21 -142 695 638 ;
238
+ C -1 ; WX 600 ; N Nacute ; B 8 -12 730 784 ;
239
+ C 238 ; WX 600 ; N icircumflex ; B 77 0 577 657 ;
240
+ C 202 ; WX 600 ; N Ecircumflex ; B 25 0 670 780 ;
241
+ C 228 ; WX 600 ; N adieresis ; B 61 -15 595 638 ;
242
+ C 235 ; WX 600 ; N edieresis ; B 81 -15 605 638 ;
243
+ C -1 ; WX 600 ; N cacute ; B 81 -15 649 661 ;
244
+ C -1 ; WX 600 ; N nacute ; B 18 0 639 661 ;
245
+ C -1 ; WX 600 ; N umacron ; B 70 -15 637 585 ;
246
+ C -1 ; WX 600 ; N Ncaron ; B 8 -12 730 790 ;
247
+ C 205 ; WX 600 ; N Iacute ; B 77 0 643 784 ;
248
+ C 177 ; WX 600 ; N plusminus ; B 76 24 614 515 ;
249
+ C 166 ; WX 600 ; N brokenbar ; B 217 -175 489 675 ;
250
+ C 174 ; WX 600 ; N registered ; B 53 -18 667 580 ;
251
+ C -1 ; WX 600 ; N Gbreve ; B 74 -18 684 784 ;
252
+ C -1 ; WX 600 ; N Idotaccent ; B 77 0 643 761 ;
253
+ C -1 ; WX 600 ; N summation ; B 15 -10 672 706 ;
254
+ C 200 ; WX 600 ; N Egrave ; B 25 0 670 784 ;
255
+ C -1 ; WX 600 ; N racute ; B 47 0 655 661 ;
256
+ C -1 ; WX 600 ; N omacron ; B 71 -15 637 585 ;
257
+ C -1 ; WX 600 ; N Zacute ; B 62 0 665 784 ;
258
+ C 142 ; WX 600 ; N Zcaron ; B 62 0 659 790 ;
259
+ C -1 ; WX 600 ; N greaterequal ; B 26 0 627 696 ;
260
+ C 208 ; WX 600 ; N Eth ; B 30 0 664 562 ;
261
+ C 199 ; WX 600 ; N Ccedilla ; B 74 -206 675 580 ;
262
+ C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 546 626 ;
263
+ C -1 ; WX 600 ; N tcaron ; B 118 -15 627 703 ;
264
+ C -1 ; WX 600 ; N eogonek ; B 81 -199 605 454 ;
265
+ C -1 ; WX 600 ; N Uogonek ; B 101 -199 716 562 ;
266
+ C 193 ; WX 600 ; N Aacute ; B -9 0 655 784 ;
267
+ C 196 ; WX 600 ; N Adieresis ; B -9 0 632 761 ;
268
+ C 232 ; WX 600 ; N egrave ; B 81 -15 605 661 ;
269
+ C -1 ; WX 600 ; N zacute ; B 81 0 614 661 ;
270
+ C -1 ; WX 600 ; N iogonek ; B 77 -199 546 658 ;
271
+ C 211 ; WX 600 ; N Oacute ; B 74 -18 645 784 ;
272
+ C 243 ; WX 600 ; N oacute ; B 71 -15 649 661 ;
273
+ C -1 ; WX 600 ; N amacron ; B 61 -15 637 585 ;
274
+ C -1 ; WX 600 ; N sacute ; B 66 -17 609 661 ;
275
+ C 239 ; WX 600 ; N idieresis ; B 77 0 561 618 ;
276
+ C 212 ; WX 600 ; N Ocircumflex ; B 74 -18 645 780 ;
277
+ C 217 ; WX 600 ; N Ugrave ; B 101 -18 716 784 ;
278
+ C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
279
+ C 254 ; WX 600 ; N thorn ; B -32 -142 622 626 ;
280
+ C 178 ; WX 600 ; N twosuperior ; B 191 230 542 616 ;
281
+ C 214 ; WX 600 ; N Odieresis ; B 74 -18 645 761 ;
282
+ C 181 ; WX 600 ; N mu ; B 49 -142 592 439 ;
283
+ C 236 ; WX 600 ; N igrave ; B 77 0 546 661 ;
284
+ C -1 ; WX 600 ; N ohungarumlaut ; B 71 -15 809 661 ;
285
+ C -1 ; WX 600 ; N Eogonek ; B 25 -199 670 562 ;
286
+ C -1 ; WX 600 ; N dcroat ; B 60 -15 712 626 ;
287
+ C 190 ; WX 600 ; N threequarters ; B 8 -60 699 661 ;
288
+ C -1 ; WX 600 ; N Scedilla ; B 54 -206 673 582 ;
289
+ C -1 ; WX 600 ; N lcaron ; B 77 0 731 626 ;
290
+ C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 692 562 ;
291
+ C -1 ; WX 600 ; N Lacute ; B 39 0 636 784 ;
292
+ C 153 ; WX 600 ; N trademark ; B 86 230 869 562 ;
293
+ C -1 ; WX 600 ; N edotaccent ; B 81 -15 605 638 ;
294
+ C 204 ; WX 600 ; N Igrave ; B 77 0 643 784 ;
295
+ C -1 ; WX 600 ; N Imacron ; B 77 0 663 708 ;
296
+ C -1 ; WX 600 ; N Lcaron ; B 39 0 757 562 ;
297
+ C 189 ; WX 600 ; N onehalf ; B 22 -60 716 661 ;
298
+ C -1 ; WX 600 ; N lessequal ; B 26 0 671 696 ;
299
+ C 244 ; WX 600 ; N ocircumflex ; B 71 -15 622 657 ;
300
+ C 241 ; WX 600 ; N ntilde ; B 18 0 643 636 ;
301
+ C -1 ; WX 600 ; N Uhungarumlaut ; B 101 -18 805 784 ;
302
+ C 201 ; WX 600 ; N Eacute ; B 25 0 670 784 ;
303
+ C -1 ; WX 600 ; N emacron ; B 81 -15 637 585 ;
304
+ C -1 ; WX 600 ; N gbreve ; B 40 -146 674 661 ;
305
+ C 188 ; WX 600 ; N onequarter ; B 13 -60 707 661 ;
306
+ C 138 ; WX 600 ; N Scaron ; B 54 -22 689 790 ;
307
+ C -1 ; WX 600 ; N Scommaaccent ; B 54 -250 673 582 ;
308
+ C -1 ; WX 600 ; N Ohungarumlaut ; B 74 -18 795 784 ;
309
+ C 176 ; WX 600 ; N degree ; B 173 243 570 616 ;
310
+ C 242 ; WX 600 ; N ograve ; B 71 -15 622 661 ;
311
+ C -1 ; WX 600 ; N Ccaron ; B 74 -18 689 790 ;
312
+ C 249 ; WX 600 ; N ugrave ; B 70 -15 592 661 ;
313
+ C -1 ; WX 600 ; N radical ; B 67 -104 635 778 ;
314
+ C -1 ; WX 600 ; N Dcaron ; B 30 0 664 790 ;
315
+ C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 655 454 ;
316
+ C 209 ; WX 600 ; N Ntilde ; B 8 -12 730 759 ;
317
+ C 245 ; WX 600 ; N otilde ; B 71 -15 643 636 ;
318
+ C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 617 562 ;
319
+ C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 636 562 ;
320
+ C 195 ; WX 600 ; N Atilde ; B -9 0 669 759 ;
321
+ C -1 ; WX 600 ; N Aogonek ; B -9 -199 632 562 ;
322
+ C 197 ; WX 600 ; N Aring ; B -9 0 632 801 ;
323
+ C 213 ; WX 600 ; N Otilde ; B 74 -18 669 759 ;
324
+ C -1 ; WX 600 ; N zdotaccent ; B 81 0 614 638 ;
325
+ C -1 ; WX 600 ; N Ecaron ; B 25 0 670 790 ;
326
+ C -1 ; WX 600 ; N Iogonek ; B 77 -199 643 562 ;
327
+ C -1 ; WX 600 ; N kcommaaccent ; B 33 -250 643 626 ;
328
+ C -1 ; WX 600 ; N minus ; B 114 203 596 313 ;
329
+ C 206 ; WX 600 ; N Icircumflex ; B 77 0 643 780 ;
330
+ C -1 ; WX 600 ; N ncaron ; B 18 0 633 667 ;
331
+ C -1 ; WX 600 ; N tcommaaccent ; B 118 -250 567 562 ;
332
+ C 172 ; WX 600 ; N logicalnot ; B 135 103 617 413 ;
333
+ C 246 ; WX 600 ; N odieresis ; B 71 -15 622 638 ;
334
+ C 252 ; WX 600 ; N udieresis ; B 70 -15 595 638 ;
335
+ C -1 ; WX 600 ; N notequal ; B 30 -47 626 563 ;
336
+ C -1 ; WX 600 ; N gcommaaccent ; B 40 -146 674 714 ;
337
+ C 240 ; WX 600 ; N eth ; B 93 -27 661 626 ;
338
+ C 158 ; WX 600 ; N zcaron ; B 81 0 643 667 ;
339
+ C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 615 454 ;
340
+ C 185 ; WX 600 ; N onesuperior ; B 212 230 514 616 ;
341
+ C -1 ; WX 600 ; N imacron ; B 77 0 575 585 ;
342
+ C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
343
+ EndCharMetrics
344
+ EndFontMetrics
dompdf/lib/fonts/Courier-Oblique.afm ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ StartFontMetrics 4.1
2
+ Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
3
+ Comment Creation Date: Thu May 0:00:00 17:37:52 1997
4
+ Comment UniqueID 43051
5
+ Comment VMusage 16248 75829
6
+ FontName Courier-Oblique
7
+ FullName Courier Oblique
8
+ FamilyName Courier
9
+ Weight Medium
10
+ ItalicAngle -12
11
+ IsFixedPitch true
12
+ CharacterSet ExtendedRoman
13
+ FontBBox -27 -250 849 805
14
+ UnderlinePosition -100
15
+ UnderlineThickness 50
16
+ Version 003.000
17
+ Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
18
+ EncodingScheme WinAnsiEncoding
19
+ CapHeight 562
20
+ XHeight 426
21
+ Ascender 629
22
+ Descender -157
23
+ StdHW 51
24
+ StdVW 51
25
+ StartCharMetrics 317
26
+ C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
27
+ C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
28
+ C 33 ; WX 600 ; N exclam ; B 243 -15 464 572 ;
29
+ C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ;
30
+ C 35 ; WX 600 ; N numbersign ; B 133 -32 596 639 ;
31
+ C 36 ; WX 600 ; N dollar ; B 108 -126 596 662 ;
32
+ C 37 ; WX 600 ; N percent ; B 134 -15 599 622 ;
33
+ C 38 ; WX 600 ; N ampersand ; B 87 -15 580 543 ;
34
+ C 146 ; WX 600 ; N quoteright ; B 283 328 495 562 ;
35
+ C 40 ; WX 600 ; N parenleft ; B 313 -108 572 622 ;
36
+ C 41 ; WX 600 ; N parenright ; B 137 -108 396 622 ;
37
+ C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ;
38
+ C 43 ; WX 600 ; N plus ; B 129 44 580 470 ;
39
+ C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ;
40
+ C 45 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
41
+ C 173 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
42
+ C 46 ; WX 600 ; N period ; B 238 -15 382 109 ;
43
+ C 47 ; WX 600 ; N slash ; B 112 -80 604 629 ;
44
+ C 48 ; WX 600 ; N zero ; B 154 -15 575 622 ;
45
+ C 49 ; WX 600 ; N one ; B 98 0 515 622 ;
46
+ C 50 ; WX 600 ; N two ; B 70 0 568 622 ;
47
+ C 51 ; WX 600 ; N three ; B 82 -15 538 622 ;
48
+ C 52 ; WX 600 ; N four ; B 108 0 541 622 ;
49
+ C 53 ; WX 600 ; N five ; B 99 -15 589 607 ;
50
+ C 54 ; WX 600 ; N six ; B 155 -15 629 622 ;
51
+ C 55 ; WX 600 ; N seven ; B 182 0 612 607 ;
52
+ C 56 ; WX 600 ; N eight ; B 132 -15 588 622 ;
53
+ C 57 ; WX 600 ; N nine ; B 93 -15 574 622 ;
54
+ C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ;
55
+ C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ;
56
+ C 60 ; WX 600 ; N less ; B 96 42 610 472 ;
57
+ C 61 ; WX 600 ; N equal ; B 109 138 600 376 ;
58
+ C 62 ; WX 600 ; N greater ; B 85 42 599 472 ;
59
+ C 63 ; WX 600 ; N question ; B 222 -15 583 572 ;
60
+ C 64 ; WX 600 ; N at ; B 127 -15 582 622 ;
61
+ C 65 ; WX 600 ; N A ; B 3 0 607 562 ;
62
+ C 66 ; WX 600 ; N B ; B 43 0 616 562 ;
63
+ C 67 ; WX 600 ; N C ; B 93 -18 655 580 ;
64
+ C 68 ; WX 600 ; N D ; B 43 0 645 562 ;
65
+ C 69 ; WX 600 ; N E ; B 53 0 660 562 ;
66
+ C 70 ; WX 600 ; N F ; B 53 0 660 562 ;
67
+ C 71 ; WX 600 ; N G ; B 83 -18 645 580 ;
68
+ C 72 ; WX 600 ; N H ; B 32 0 687 562 ;
69
+ C 73 ; WX 600 ; N I ; B 96 0 623 562 ;
70
+ C 74 ; WX 600 ; N J ; B 52 -18 685 562 ;
71
+ C 75 ; WX 600 ; N K ; B 38 0 671 562 ;
72
+ C 76 ; WX 600 ; N L ; B 47 0 607 562 ;
73
+ C 77 ; WX 600 ; N M ; B 4 0 715 562 ;
74
+ C 78 ; WX 600 ; N N ; B 7 -13 712 562 ;
75
+ C 79 ; WX 600 ; N O ; B 94 -18 625 580 ;
76
+ C 80 ; WX 600 ; N P ; B 79 0 644 562 ;
77
+ C 81 ; WX 600 ; N Q ; B 95 -138 625 580 ;
78
+ C 82 ; WX 600 ; N R ; B 38 0 598 562 ;
79
+ C 83 ; WX 600 ; N S ; B 76 -20 650 580 ;
80
+ C 84 ; WX 600 ; N T ; B 108 0 665 562 ;
81
+ C 85 ; WX 600 ; N U ; B 125 -18 702 562 ;
82
+ C 86 ; WX 600 ; N V ; B 105 -13 723 562 ;
83
+ C 87 ; WX 600 ; N W ; B 106 -13 722 562 ;
84
+ C 88 ; WX 600 ; N X ; B 23 0 675 562 ;
85
+ C 89 ; WX 600 ; N Y ; B 133 0 695 562 ;
86
+ C 90 ; WX 600 ; N Z ; B 86 0 610 562 ;
87
+ C 91 ; WX 600 ; N bracketleft ; B 246 -108 574 622 ;
88
+ C 92 ; WX 600 ; N backslash ; B 249 -80 468 629 ;
89
+ C 93 ; WX 600 ; N bracketright ; B 135 -108 463 622 ;
90
+ C 94 ; WX 600 ; N asciicircum ; B 175 354 587 622 ;
91
+ C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
92
+ C 145 ; WX 600 ; N quoteleft ; B 343 328 457 562 ;
93
+ C 97 ; WX 600 ; N a ; B 76 -15 569 441 ;
94
+ C 98 ; WX 600 ; N b ; B 29 -15 625 629 ;
95
+ C 99 ; WX 600 ; N c ; B 106 -15 608 441 ;
96
+ C 100 ; WX 600 ; N d ; B 85 -15 640 629 ;
97
+ C 101 ; WX 600 ; N e ; B 106 -15 598 441 ;
98
+ C 102 ; WX 600 ; N f ; B 114 0 662 629 ; L i fi ; L l fl ;
99
+ C 103 ; WX 600 ; N g ; B 61 -157 657 441 ;
100
+ C 104 ; WX 600 ; N h ; B 33 0 592 629 ;
101
+ C 105 ; WX 600 ; N i ; B 95 0 515 657 ;
102
+ C 106 ; WX 600 ; N j ; B 52 -157 550 657 ;
103
+ C 107 ; WX 600 ; N k ; B 58 0 633 629 ;
104
+ C 108 ; WX 600 ; N l ; B 95 0 515 629 ;
105
+ C 109 ; WX 600 ; N m ; B -5 0 615 441 ;
106
+ C 110 ; WX 600 ; N n ; B 26 0 585 441 ;
107
+ C 111 ; WX 600 ; N o ; B 102 -15 588 441 ;
108
+ C 112 ; WX 600 ; N p ; B -24 -157 605 441 ;
109
+ C 113 ; WX 600 ; N q ; B 85 -157 682 441 ;
110
+ C 114 ; WX 600 ; N r ; B 60 0 636 441 ;
111
+ C 115 ; WX 600 ; N s ; B 78 -15 584 441 ;
112
+ C 116 ; WX 600 ; N t ; B 167 -15 561 561 ;
113
+ C 117 ; WX 600 ; N u ; B 101 -15 572 426 ;
114
+ C 118 ; WX 600 ; N v ; B 90 -10 681 426 ;
115
+ C 119 ; WX 600 ; N w ; B 76 -10 695 426 ;
116
+ C 120 ; WX 600 ; N x ; B 20 0 655 426 ;
117
+ C 121 ; WX 600 ; N y ; B -4 -157 683 426 ;
118
+ C 122 ; WX 600 ; N z ; B 99 0 593 426 ;
119
+ C 123 ; WX 600 ; N braceleft ; B 233 -108 569 622 ;
120
+ C 124 ; WX 600 ; N bar ; B 222 -250 485 750 ;
121
+ C 125 ; WX 600 ; N braceright ; B 140 -108 477 622 ;
122
+ C 126 ; WX 600 ; N asciitilde ; B 116 197 600 320 ;
123
+ C 161 ; WX 600 ; N exclamdown ; B 225 -157 445 430 ;
124
+ C 162 ; WX 600 ; N cent ; B 151 -49 588 614 ;
125
+ C 163 ; WX 600 ; N sterling ; B 124 -21 621 611 ;
126
+ C -1 ; WX 600 ; N fraction ; B 84 -57 646 665 ;
127
+ C 165 ; WX 600 ; N yen ; B 120 0 693 562 ;
128
+ C 131 ; WX 600 ; N florin ; B -26 -143 671 622 ;
129
+ C 167 ; WX 600 ; N section ; B 104 -78 590 580 ;
130
+ C 164 ; WX 600 ; N currency ; B 94 58 628 506 ;
131
+ C 39 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
132
+ C 147 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ;
133
+ C 170 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
134
+ C 139 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
135
+ C 155 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
136
+ C -1 ; WX 600 ; N fi ; B 3 0 619 629 ;
137
+ C -1 ; WX 600 ; N fl ; B 3 0 619 629 ;
138
+ C 150 ; WX 600 ; N endash ; B 124 231 586 285 ;
139
+ C 134 ; WX 600 ; N dagger ; B 217 -78 546 580 ;
140
+ C 135 ; WX 600 ; N daggerdbl ; B 163 -78 546 580 ;
141
+ C 183 ; WX 600 ; N periodcentered ; B 275 189 434 327 ;
142
+ C 182 ; WX 600 ; N paragraph ; B 100 -78 630 562 ;
143
+ C 149 ; WX 600 ; N bullet ; B 224 130 485 383 ;
144
+ C 130 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ;
145
+ C 132 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ;
146
+ C 148 ; WX 600 ; N quotedblright ; B 213 328 576 562 ;
147
+ C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ;
148
+ C 133 ; WX 600 ; N ellipsis ; B 46 -15 575 111 ;
149
+ C 137 ; WX 600 ; N perthousand ; B 59 -15 627 622 ;
150
+ C 191 ; WX 600 ; N questiondown ; B 105 -157 466 430 ;
151
+ C 96 ; WX 600 ; N grave ; B 294 497 484 672 ;
152
+ C 180 ; WX 600 ; N acute ; B 348 497 612 672 ;
153
+ C 136 ; WX 600 ; N circumflex ; B 229 477 581 654 ;
154
+ C 152 ; WX 600 ; N tilde ; B 212 489 629 606 ;
155
+ C 175 ; WX 600 ; N macron ; B 232 525 600 565 ;
156
+ C -1 ; WX 600 ; N breve ; B 279 501 576 609 ;
157
+ C -1 ; WX 600 ; N dotaccent ; B 373 537 478 640 ;
158
+ C 168 ; WX 600 ; N dieresis ; B 272 537 579 640 ;
159
+ C -1 ; WX 600 ; N ring ; B 332 463 500 627 ;
160
+ C 184 ; WX 600 ; N cedilla ; B 197 -151 344 10 ;
161
+ C -1 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ;
162
+ C -1 ; WX 600 ; N ogonek ; B 189 -172 377 4 ;
163
+ C -1 ; WX 600 ; N caron ; B 262 492 614 669 ;
164
+ C 151 ; WX 600 ; N emdash ; B 49 231 661 285 ;
165
+ C 198 ; WX 600 ; N AE ; B 3 0 655 562 ;
166
+ C 170 ; WX 600 ; N ordfeminine ; B 209 249 512 580 ;
167
+ C -1 ; WX 600 ; N Lslash ; B 47 0 607 562 ;
168
+ C 216 ; WX 600 ; N Oslash ; B 94 -80 625 629 ;
169
+ C 140 ; WX 600 ; N OE ; B 59 0 672 562 ;
170
+ C 186 ; WX 600 ; N ordmasculine ; B 210 249 535 580 ;
171
+ C 230 ; WX 600 ; N ae ; B 41 -15 626 441 ;
172
+ C -1 ; WX 600 ; N dotlessi ; B 95 0 515 426 ;
173
+ C -1 ; WX 600 ; N lslash ; B 95 0 587 629 ;
174
+ C 248 ; WX 600 ; N oslash ; B 102 -80 588 506 ;
175
+ C 156 ; WX 600 ; N oe ; B 54 -15 615 441 ;
176
+ C 223 ; WX 600 ; N germandbls ; B 48 -15 617 629 ;
177
+ C 207 ; WX 600 ; N Idieresis ; B 96 0 623 753 ;
178
+ C 233 ; WX 600 ; N eacute ; B 106 -15 612 672 ;
179
+ C -1 ; WX 600 ; N abreve ; B 76 -15 576 609 ;
180
+ C -1 ; WX 600 ; N uhungarumlaut ; B 101 -15 723 672 ;
181
+ C -1 ; WX 600 ; N ecaron ; B 106 -15 614 669 ;
182
+ C 159 ; WX 600 ; N Ydieresis ; B 133 0 695 753 ;
183
+ C 247 ; WX 600 ; N divide ; B 136 48 573 467 ;
184
+ C 221 ; WX 600 ; N Yacute ; B 133 0 695 805 ;
185
+ C 194 ; WX 600 ; N Acircumflex ; B 3 0 607 787 ;
186
+ C 225 ; WX 600 ; N aacute ; B 76 -15 612 672 ;
187
+ C 219 ; WX 600 ; N Ucircumflex ; B 125 -18 702 787 ;
188
+ C 253 ; WX 600 ; N yacute ; B -4 -157 683 672 ;
189
+ C -1 ; WX 600 ; N scommaaccent ; B 78 -250 584 441 ;
190
+ C 234 ; WX 600 ; N ecircumflex ; B 106 -15 598 654 ;
191
+ C -1 ; WX 600 ; N Uring ; B 125 -18 702 760 ;
192
+ C 220 ; WX 600 ; N Udieresis ; B 125 -18 702 753 ;
193
+ C -1 ; WX 600 ; N aogonek ; B 76 -172 569 441 ;
194
+ C 218 ; WX 600 ; N Uacute ; B 125 -18 702 805 ;
195
+ C -1 ; WX 600 ; N uogonek ; B 101 -172 572 426 ;
196
+ C 203 ; WX 600 ; N Edieresis ; B 53 0 660 753 ;
197
+ C -1 ; WX 600 ; N Dcroat ; B 43 0 645 562 ;
198
+ C -1 ; WX 600 ; N commaaccent ; B 145 -250 323 -58 ;
199
+ C 169 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
200
+ C -1 ; WX 600 ; N Emacron ; B 53 0 660 698 ;
201
+ C -1 ; WX 600 ; N ccaron ; B 106 -15 614 669 ;
202
+ C 229 ; WX 600 ; N aring ; B 76 -15 569 627 ;
203
+ C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 712 562 ;
204
+ C -1 ; WX 600 ; N lacute ; B 95 0 640 805 ;
205
+ C 224 ; WX 600 ; N agrave ; B 76 -15 569 672 ;
206
+ C -1 ; WX 600 ; N Tcommaaccent ; B 108 -250 665 562 ;
207
+ C -1 ; WX 600 ; N Cacute ; B 93 -18 655 805 ;
208
+ C 227 ; WX 600 ; N atilde ; B 76 -15 629 606 ;
209
+ C -1 ; WX 600 ; N Edotaccent ; B 53 0 660 753 ;
210
+ C 154 ; WX 600 ; N scaron ; B 78 -15 614 669 ;
211
+ C -1 ; WX 600 ; N scedilla ; B 78 -151 584 441 ;
212
+ C 237 ; WX 600 ; N iacute ; B 95 0 612 672 ;
213
+ C -1 ; WX 600 ; N lozenge ; B 94 0 519 706 ;
214
+ C -1 ; WX 600 ; N Rcaron ; B 38 0 642 802 ;
215
+ C -1 ; WX 600 ; N Gcommaaccent ; B 83 -250 645 580 ;
216
+ C 251 ; WX 600 ; N ucircumflex ; B 101 -15 572 654 ;
217
+ C 226 ; WX 600 ; N acircumflex ; B 76 -15 581 654 ;
218
+ C -1 ; WX 600 ; N Amacron ; B 3 0 607 698 ;
219
+ C -1 ; WX 600 ; N rcaron ; B 60 0 636 669 ;
220
+ C 231 ; WX 600 ; N ccedilla ; B 106 -151 614 441 ;
221
+ C -1 ; WX 600 ; N Zdotaccent ; B 86 0 610 753 ;
222
+ C 222 ; WX 600 ; N Thorn ; B 79 0 606 562 ;
223
+ C -1 ; WX 600 ; N Omacron ; B 94 -18 628 698 ;
224
+ C -1 ; WX 600 ; N Racute ; B 38 0 670 805 ;
225
+ C -1 ; WX 600 ; N Sacute ; B 76 -20 650 805 ;
226
+ C -1 ; WX 600 ; N dcaron ; B 85 -15 849 629 ;
227
+ C -1 ; WX 600 ; N Umacron ; B 125 -18 702 698 ;
228
+ C -1 ; WX 600 ; N uring ; B 101 -15 572 627 ;
229
+ C 179 ; WX 600 ; N threesuperior ; B 213 240 501 622 ;
230
+ C 210 ; WX 600 ; N Ograve ; B 94 -18 625 805 ;
231
+ C 192 ; WX 600 ; N Agrave ; B 3 0 607 805 ;
232
+ C -1 ; WX 600 ; N Abreve ; B 3 0 607 732 ;
233
+ C 215 ; WX 600 ; N multiply ; B 103 43 607 470 ;
234
+ C 250 ; WX 600 ; N uacute ; B 101 -15 602 672 ;
235
+ C -1 ; WX 600 ; N Tcaron ; B 108 0 665 802 ;
236
+ C -1 ; WX 600 ; N partialdiff ; B 45 -38 546 710 ;
237
+ C 255 ; WX 600 ; N ydieresis ; B -4 -157 683 620 ;
238
+ C -1 ; WX 600 ; N Nacute ; B 7 -13 712 805 ;
239
+ C 238 ; WX 600 ; N icircumflex ; B 95 0 551 654 ;
240
+ C 202 ; WX 600 ; N Ecircumflex ; B 53 0 660 787 ;
241
+ C 228 ; WX 600 ; N adieresis ; B 76 -15 575 620 ;
242
+ C 235 ; WX 600 ; N edieresis ; B 106 -15 598 620 ;
243
+ C -1 ; WX 600 ; N cacute ; B 106 -15 612 672 ;
244
+ C -1 ; WX 600 ; N nacute ; B 26 0 602 672 ;
245
+ C -1 ; WX 600 ; N umacron ; B 101 -15 600 565 ;
246
+ C -1 ; WX 600 ; N Ncaron ; B 7 -13 712 802 ;
247
+ C 205 ; WX 600 ; N Iacute ; B 96 0 640 805 ;
248
+ C 177 ; WX 600 ; N plusminus ; B 96 44 594 558 ;
249
+ C 166 ; WX 600 ; N brokenbar ; B 238 -175 469 675 ;
250
+ C 174 ; WX 600 ; N registered ; B 53 -18 667 580 ;
251
+ C -1 ; WX 600 ; N Gbreve ; B 83 -18 645 732 ;
252
+ C -1 ; WX 600 ; N Idotaccent ; B 96 0 623 753 ;
253
+ C -1 ; WX 600 ; N summation ; B 15 -10 670 706 ;
254
+ C 200 ; WX 600 ; N Egrave ; B 53 0 660 805 ;
255
+ C -1 ; WX 600 ; N racute ; B 60 0 636 672 ;
256
+ C -1 ; WX 600 ; N omacron ; B 102 -15 600 565 ;
257
+ C -1 ; WX 600 ; N Zacute ; B 86 0 670 805 ;
258
+ C 142 ; WX 600 ; N Zcaron ; B 86 0 642 802 ;
259
+ C -1 ; WX 600 ; N greaterequal ; B 98 0 594 710 ;
260
+ C 208 ; WX 600 ; N Eth ; B 43 0 645 562 ;
261
+ C 199 ; WX 600 ; N Ccedilla ; B 93 -151 658 580 ;
262
+ C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 515 629 ;
263
+ C -1 ; WX 600 ; N tcaron ; B 167 -15 587 717 ;
264
+ C -1 ; WX 600 ; N eogonek ; B 106 -172 598 441 ;
265
+ C -1 ; WX 600 ; N Uogonek ; B 124 -172 702 562 ;
266
+ C 193 ; WX 600 ; N Aacute ; B 3 0 660 805 ;
267
+ C 196 ; WX 600 ; N Adieresis ; B 3 0 607 753 ;
268
+ C 232 ; WX 600 ; N egrave ; B 106 -15 598 672 ;
269
+ C -1 ; WX 600 ; N zacute ; B 99 0 612 672 ;
270
+ C -1 ; WX 600 ; N iogonek ; B 95 -172 515 657 ;
271
+ C 211 ; WX 600 ; N Oacute ; B 94 -18 640 805 ;
272
+ C 243 ; WX 600 ; N oacute ; B 102 -15 612 672 ;
273
+ C -1 ; WX 600 ; N amacron ; B 76 -15 600 565 ;
274
+ C -1 ; WX 600 ; N sacute ; B 78 -15 612 672 ;
275
+ C 239 ; WX 600 ; N idieresis ; B 95 0 545 620 ;
276
+ C 212 ; WX 600 ; N Ocircumflex ; B 94 -18 625 787 ;
277
+ C 217 ; WX 600 ; N Ugrave ; B 125 -18 702 805 ;
278
+ C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
279
+ C 254 ; WX 600 ; N thorn ; B -24 -157 605 629 ;
280
+ C 178 ; WX 600 ; N twosuperior ; B 230 249 535 622 ;
281
+ C 214 ; WX 600 ; N Odieresis ; B 94 -18 625 753 ;
282
+ C 181 ; WX 600 ; N mu ; B 72 -157 572 426 ;
283
+ C 236 ; WX 600 ; N igrave ; B 95 0 515 672 ;
284
+ C -1 ; WX 600 ; N ohungarumlaut ; B 102 -15 723 672 ;
285
+ C -1 ; WX 600 ; N Eogonek ; B 53 -172 660 562 ;
286
+ C -1 ; WX 600 ; N dcroat ; B 85 -15 704 629 ;
287
+ C 190 ; WX 600 ; N threequarters ; B 73 -56 659 666 ;
288
+ C -1 ; WX 600 ; N Scedilla ; B 76 -151 650 580 ;
289
+ C -1 ; WX 600 ; N lcaron ; B 95 0 667 629 ;
290
+ C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 671 562 ;
291
+ C -1 ; WX 600 ; N Lacute ; B 47 0 607 805 ;
292
+ C 153 ; WX 600 ; N trademark ; B 75 263 742 562 ;
293
+ C -1 ; WX 600 ; N edotaccent ; B 106 -15 598 620 ;
294
+ C 204 ; WX 600 ; N Igrave ; B 96 0 623 805 ;
295
+ C -1 ; WX 600 ; N Imacron ; B 96 0 628 698 ;
296
+ C -1 ; WX 600 ; N Lcaron ; B 47 0 632 562 ;
297
+ C 189 ; WX 600 ; N onehalf ; B 65 -57 669 665 ;
298
+ C -1 ; WX 600 ; N lessequal ; B 98 0 645 710 ;
299
+ C 244 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ;
300
+ C 241 ; WX 600 ; N ntilde ; B 26 0 629 606 ;
301
+ C -1 ; WX 600 ; N Uhungarumlaut ; B 125 -18 761 805 ;
302
+ C 201 ; WX 600 ; N Eacute ; B 53 0 670 805 ;
303
+ C -1 ; WX 600 ; N emacron ; B 106 -15 600 565 ;
304
+ C -1 ; WX 600 ; N gbreve ; B 61 -157 657 609 ;
305
+ C 188 ; WX 600 ; N onequarter ; B 65 -57 674 665 ;
306
+ C 138 ; WX 600 ; N Scaron ; B 76 -20 672 802 ;
307
+ C -1 ; WX 600 ; N Scommaaccent ; B 76 -250 650 580 ;
308
+ C -1 ; WX 600 ; N Ohungarumlaut ; B 94 -18 751 805 ;
309
+ C 176 ; WX 600 ; N degree ; B 214 269 576 622 ;
310
+ C 242 ; WX 600 ; N ograve ; B 102 -15 588 672 ;
311
+ C -1 ; WX 600 ; N Ccaron ; B 93 -18 672 802 ;
312
+ C 249 ; WX 600 ; N ugrave ; B 101 -15 572 672 ;
313
+ C -1 ; WX 600 ; N radical ; B 85 -15 765 792 ;
314
+ C -1 ; WX 600 ; N Dcaron ; B 43 0 645 802 ;
315
+ C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 636 441 ;
316
+ C 209 ; WX 600 ; N Ntilde ; B 7 -13 712 729 ;
317
+ C 245 ; WX 600 ; N otilde ; B 102 -15 629 606 ;
318
+ C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 598 562 ;
319
+ C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 607 562 ;
320
+ C 195 ; WX 600 ; N Atilde ; B 3 0 655 729 ;
321
+ C -1 ; WX 600 ; N Aogonek ; B 3 -172 607 562 ;
322
+ C 197 ; WX 600 ; N Aring ; B 3 0 607 750 ;
323
+ C 213 ; WX 600 ; N Otilde ; B 94 -18 655 729 ;
324
+ C -1 ; WX 600 ; N zdotaccent ; B 99 0 593 620 ;
325
+ C -1 ; WX 600 ; N Ecaron ; B 53 0 660 802 ;
326
+ C -1 ; WX 600 ; N Iogonek ; B 96 -172 623 562 ;
327
+ C -1 ; WX 600 ; N kcommaaccent ; B 58 -250 633 629 ;
328
+ C -1 ; WX 600 ; N minus ; B 129 232 580 283 ;
329
+ C 206 ; WX 600 ; N Icircumflex ; B 96 0 623 787 ;
330
+ C -1 ; WX 600 ; N ncaron ; B 26 0 614 669 ;
331
+ C -1 ; WX 600 ; N tcommaaccent ; B 165 -250 561 561 ;
332
+ C 172 ; WX 600 ; N logicalnot ; B 155 108 591 369 ;
333
+ C 246 ; WX 600 ; N odieresis ; B 102 -15 588 620 ;
334
+ C 252 ; WX 600 ; N udieresis ; B 101 -15 575 620 ;
335
+ C -1 ; WX 600 ; N notequal ; B 43 -16 621 529 ;
336
+ C -1 ; WX 600 ; N gcommaaccent ; B 61 -157 657 708 ;
337
+ C 240 ; WX 600 ; N eth ; B 102 -15 639 629 ;
338
+ C 158 ; WX 600 ; N zcaron ; B 99 0 624 669 ;
339
+ C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 585 441 ;
340
+ C 185 ; WX 600 ; N onesuperior ; B 231 249 491 622 ;
341
+ C -1 ; WX 600 ; N imacron ; B 95 0 543 565 ;
342
+ C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
343
+ EndCharMetrics
344
+ EndFontMetrics
dompdf/lib/fonts/Courier.afm ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ StartFontMetrics 4.1
2
+ Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
3
+ Comment Creation Date: Thu May 1 17:27:09 1997
4
+ Comment UniqueID 43050
5
+ Comment VMusage 39754 50779
6
+ FontName Courier
7
+ FullName Courier
8
+ FamilyName Courier
9
+ Weight Medium
10
+ ItalicAngle 0
11
+ IsFixedPitch true
12
+ CharacterSet ExtendedRoman
13
+ FontBBox -23 -250 715 805
14
+ UnderlinePosition -100
15
+ UnderlineThickness 50
16
+ Version 003.000
17
+ Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
18
+ EncodingScheme WinAnsiEncoding
19
+ CapHeight 562
20
+ XHeight 426
21
+ Ascender 629
22
+ Descender -157
23
+ StdHW 51
24
+ StdVW 51
25
+ StartCharMetrics 317
26
+ C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
27
+ C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
28
+ C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ;
29
+ C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ;
30
+ C 35 ; WX 600 ; N numbersign ; B 93 -32 507 639 ;
31
+ C 36 ; WX 600 ; N dollar ; B 105 -126 496 662 ;
32
+ C 37 ; WX 600 ; N percent ; B 81 -15 518 622 ;
33
+ C 38 ; WX 600 ; N ampersand ; B 63 -15 538 543 ;
34
+ C 146 ; WX 600 ; N quoteright ; B 213 328 376 562 ;
35
+ C 40 ; WX 600 ; N parenleft ; B 269 -108 440 622 ;
36
+ C 41 ; WX 600 ; N parenright ; B 160 -108 331 622 ;
37
+ C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ;
38
+ C 43 ; WX 600 ; N plus ; B 80 44 520 470 ;
39
+ C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ;
40
+ C 45 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
41
+ C 173 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
42
+ C 46 ; WX 600 ; N period ; B 229 -15 371 109 ;
43
+ C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ;
44
+ C 48 ; WX 600 ; N zero ; B 106 -15 494 622 ;
45
+ C 49 ; WX 600 ; N one ; B 96 0 505 622 ;
46
+ C 50 ; WX 600 ; N two ; B 70 0 471 622 ;
47
+ C 51 ; WX 600 ; N three ; B 75 -15 466 622 ;
48
+ C 52 ; WX 600 ; N four ; B 78 0 500 622 ;
49
+ C 53 ; WX 600 ; N five ; B 92 -15 497 607 ;
50
+ C 54 ; WX 600 ; N six ; B 111 -15 497 622 ;
51
+ C 55 ; WX 600 ; N seven ; B 82 0 483 607 ;
52
+ C 56 ; WX 600 ; N eight ; B 102 -15 498 622 ;
53
+ C 57 ; WX 600 ; N nine ; B 96 -15 489 622 ;
54
+ C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ;
55
+ C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ;
56
+ C 60 ; WX 600 ; N less ; B 41 42 519 472 ;
57
+ C 61 ; WX 600 ; N equal ; B 80 138 520 376 ;
58
+ C 62 ; WX 600 ; N greater ; B 66 42 544 472 ;
59
+ C 63 ; WX 600 ; N question ; B 129 -15 492 572 ;
60
+ C 64 ; WX 600 ; N at ; B 77 -15 533 622 ;
61
+ C 65 ; WX 600 ; N A ; B 3 0 597 562 ;
62
+ C 66 ; WX 600 ; N B ; B 43 0 559 562 ;
63
+ C 67 ; WX 600 ; N C ; B 41 -18 540 580 ;
64
+ C 68 ; WX 600 ; N D ; B 43 0 574 562 ;
65
+ C 69 ; WX 600 ; N E ; B 53 0 550 562 ;
66
+ C 70 ; WX 600 ; N F ; B 53 0 545 562 ;
67
+ C 71 ; WX 600 ; N G ; B 31 -18 575 580 ;
68
+ C 72 ; WX 600 ; N H ; B 32 0 568 562 ;
69
+ C 73 ; WX 600 ; N I ; B 96 0 504 562 ;
70
+ C 74 ; WX 600 ; N J ; B 34 -18 566 562 ;
71
+ C 75 ; WX 600 ; N K ; B 38 0 582 562 ;
72
+ C 76 ; WX 600 ; N L ; B 47 0 554 562 ;
73
+ C 77 ; WX 600 ; N M ; B 4 0 596 562 ;
74
+ C 78 ; WX 600 ; N N ; B 7 -13 593 562 ;
75
+ C 79 ; WX 600 ; N O ; B 43 -18 557 580 ;
76
+ C 80 ; WX 600 ; N P ; B 79 0 558 562 ;
77
+ C 81 ; WX 600 ; N Q ; B 43 -138 557 580 ;
78
+ C 82 ; WX 600 ; N R ; B 38 0 588 562 ;
79
+ C 83 ; WX 600 ; N S ; B 72 -20 529 580 ;
80
+ C 84 ; WX 600 ; N T ; B 38 0 563 562 ;
81
+ C 85 ; WX 600 ; N U ; B 17 -18 583 562 ;
82
+ C 86 ; WX 600 ; N V ; B -4 -13 604 562 ;
83
+ C 87 ; WX 600 ; N W ; B -3 -13 603 562 ;
84
+ C 88 ; WX 600 ; N X ; B 23 0 577 562 ;
85
+ C 89 ; WX 600 ; N Y ; B 24 0 576 562 ;
86
+ C 90 ; WX 600 ; N Z ; B 86 0 514 562 ;
87
+ C 91 ; WX 600 ; N bracketleft ; B 269 -108 442 622 ;
88
+ C 92 ; WX 600 ; N backslash ; B 118 -80 482 629 ;
89
+ C 93 ; WX 600 ; N bracketright ; B 158 -108 331 622 ;
90
+ C 94 ; WX 600 ; N asciicircum ; B 94 354 506 622 ;
91
+ C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
92
+ C 145 ; WX 600 ; N quoteleft ; B 224 328 387 562 ;
93
+ C 97 ; WX 600 ; N a ; B 53 -15 559 441 ;
94
+ C 98 ; WX 600 ; N b ; B 14 -15 575 629 ;
95
+ C 99 ; WX 600 ; N c ; B 66 -15 529 441 ;
96
+ C 100 ; WX 600 ; N d ; B 45 -15 591 629 ;
97
+ C 101 ; WX 600 ; N e ; B 66 -15 548 441 ;
98
+ C 102 ; WX 600 ; N f ; B 114 0 531 629 ; L i fi ; L l fl ;
99
+ C 103 ; WX 600 ; N g ; B 45 -157 566 441 ;
100
+ C 104 ; WX 600 ; N h ; B 18 0 582 629 ;
101
+ C 105 ; WX 600 ; N i ; B 95 0 505 657 ;
102
+ C 106 ; WX 600 ; N j ; B 82 -157 410 657 ;
103
+ C 107 ; WX 600 ; N k ; B 43 0 580 629 ;
104
+ C 108 ; WX 600 ; N l ; B 95 0 505 629 ;
105
+ C 109 ; WX 600 ; N m ; B -5 0 605 441 ;
106
+ C 110 ; WX 600 ; N n ; B 26 0 575 441 ;
107
+ C 111 ; WX 600 ; N o ; B 62 -15 538 441 ;
108
+ C 112 ; WX 600 ; N p ; B 9 -157 555 441 ;
109
+ C 113 ; WX 600 ; N q ; B 45 -157 591 441 ;
110
+ C 114 ; WX 600 ; N r ; B 60 0 559 441 ;
111
+ C 115 ; WX 600 ; N s ; B 80 -15 513 441 ;
112
+ C 116 ; WX 600 ; N t ; B 87 -15 530 561 ;
113
+ C 117 ; WX 600 ; N u ; B 21 -15 562 426 ;
114
+ C 118 ; WX 600 ; N v ; B 10 -10 590 426 ;
115
+ C 119 ; WX 600 ; N w ; B -4 -10 604 426 ;
116
+ C 120 ; WX 600 ; N x ; B 20 0 580 426 ;
117
+ C 121 ; WX 600 ; N y ; B 7 -157 592 426 ;
118
+ C 122 ; WX 600 ; N z ; B 99 0 502 426 ;
119
+ C 123 ; WX 600 ; N braceleft ; B 182 -108 437 622 ;
120
+ C 124 ; WX 600 ; N bar ; B 275 -250 326 750 ;
121
+ C 125 ; WX 600 ; N braceright ; B 163 -108 418 622 ;
122
+ C 126 ; WX 600 ; N asciitilde ; B 63 197 540 320 ;
123
+ C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ;
124
+ C 162 ; WX 600 ; N cent ; B 96 -49 500 614 ;
125
+ C 163 ; WX 600 ; N sterling ; B 84 -21 521 611 ;
126
+ C -1 ; WX 600 ; N fraction ; B 92 -57 509 665 ;
127
+ C 165 ; WX 600 ; N yen ; B 26 0 574 562 ;
128
+ C 131 ; WX 600 ; N florin ; B 4 -143 539 622 ;
129
+ C 167 ; WX 600 ; N section ; B 113 -78 488 580 ;
130
+ C 164 ; WX 600 ; N currency ; B 73 58 527 506 ;
131
+ C 39 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
132
+ C 147 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ;
133
+ C 170 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
134
+ C 139 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
135
+ C 155 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
136
+ C -1 ; WX 600 ; N fi ; B 3 0 597 629 ;
137
+ C -1 ; WX 600 ; N fl ; B 3 0 597 629 ;
138
+ C 150 ; WX 600 ; N endash ; B 75 231 525 285 ;
139
+ C 134 ; WX 600 ; N dagger ; B 141 -78 459 580 ;
140
+ C 135 ; WX 600 ; N daggerdbl ; B 141 -78 459 580 ;
141
+ C 183 ; WX 600 ; N periodcentered ; B 222 189 378 327 ;
142
+ C 182 ; WX 600 ; N paragraph ; B 50 -78 511 562 ;
143
+ C 149 ; WX 600 ; N bullet ; B 172 130 428 383 ;
144
+ C 130 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ;
145
+ C 132 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ;
146
+ C 148 ; WX 600 ; N quotedblright ; B 143 328 457 562 ;
147
+ C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ;
148
+ C 133 ; WX 600 ; N ellipsis ; B 37 -15 563 111 ;
149
+ C 137 ; WX 600 ; N perthousand ; B 3 -15 600 622 ;
150
+ C 191 ; WX 600 ; N questiondown ; B 108 -157 471 430 ;
151
+ C 96 ; WX 600 ; N grave ; B 151 497 378 672 ;
152
+ C 180 ; WX 600 ; N acute ; B 242 497 469 672 ;
153
+ C 136 ; WX 600 ; N circumflex ; B 124 477 476 654 ;
154
+ C 152 ; WX 600 ; N tilde ; B 105 489 503 606 ;
155
+ C 175 ; WX 600 ; N macron ; B 120 525 480 565 ;
156
+ C -1 ; WX 600 ; N breve ; B 153 501 447 609 ;
157
+ C -1 ; WX 600 ; N dotaccent ; B 249 537 352 640 ;
158
+ C 168 ; WX 600 ; N dieresis ; B 148 537 453 640 ;
159
+ C -1 ; WX 600 ; N ring ; B 218 463 382 627 ;
160
+ C 184 ; WX 600 ; N cedilla ; B 224 -151 362 10 ;
161
+ C -1 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ;
162
+ C -1 ; WX 600 ; N ogonek ; B 211 -172 407 4 ;
163
+ C -1 ; WX 600 ; N caron ; B 124 492 476 669 ;
164
+ C 151 ; WX 600 ; N emdash ; B 0 231 600 285 ;
165
+ C 198 ; WX 600 ; N AE ; B 3 0 550 562 ;
166
+ C 170 ; WX 600 ; N ordfeminine ; B 156 249 442 580 ;
167
+ C -1 ; WX 600 ; N Lslash ; B 47 0 554 562 ;
168
+ C 216 ; WX 600 ; N Oslash ; B 43 -80 557 629 ;
169
+ C 140 ; WX 600 ; N OE ; B 7 0 567 562 ;
170
+ C 186 ; WX 600 ; N ordmasculine ; B 157 249 443 580 ;
171
+ C 230 ; WX 600 ; N ae ; B 19 -15 570 441 ;
172
+ C -1 ; WX 600 ; N dotlessi ; B 95 0 505 426 ;
173
+ C -1 ; WX 600 ; N lslash ; B 95 0 505 629 ;
174
+ C 248 ; WX 600 ; N oslash ; B 62 -80 538 506 ;
175
+ C 156 ; WX 600 ; N oe ; B 19 -15 559 441 ;
176
+ C 223 ; WX 600 ; N germandbls ; B 48 -15 588 629 ;
177
+ C 207 ; WX 600 ; N Idieresis ; B 96 0 504 753 ;
178
+ C 233 ; WX 600 ; N eacute ; B 66 -15 548 672 ;
179
+ C -1 ; WX 600 ; N abreve ; B 53 -15 559 609 ;
180
+ C -1 ; WX 600 ; N uhungarumlaut ; B 21 -15 580 672 ;
181
+ C -1 ; WX 600 ; N ecaron ; B 66 -15 548 669 ;
182
+ C 159 ; WX 600 ; N Ydieresis ; B 24 0 576 753 ;
183
+ C 247 ; WX 600 ; N divide ; B 87 48 513 467 ;
184
+ C 221 ; WX 600 ; N Yacute ; B 24 0 576 805 ;
185
+ C 194 ; WX 600 ; N Acircumflex ; B 3 0 597 787 ;
186
+ C 225 ; WX 600 ; N aacute ; B 53 -15 559 672 ;
187
+ C 219 ; WX 600 ; N Ucircumflex ; B 17 -18 583 787 ;
188
+ C 253 ; WX 600 ; N yacute ; B 7 -157 592 672 ;
189
+ C -1 ; WX 600 ; N scommaaccent ; B 80 -250 513 441 ;
190
+ C 234 ; WX 600 ; N ecircumflex ; B 66 -15 548 654 ;
191
+ C -1 ; WX 600 ; N Uring ; B 17 -18 583 760 ;
192
+ C 220 ; WX 600 ; N Udieresis ; B 17 -18 583 753 ;
193
+ C -1 ; WX 600 ; N aogonek ; B 53 -172 587 441 ;
194
+ C 218 ; WX 600 ; N Uacute ; B 17 -18 583 805 ;
195
+ C -1 ; WX 600 ; N uogonek ; B 21 -172 590 426 ;
196
+ C 203 ; WX 600 ; N Edieresis ; B 53 0 550 753 ;
197
+ C -1 ; WX 600 ; N Dcroat ; B 30 0 574 562 ;
198
+ C -1 ; WX 600 ; N commaaccent ; B 198 -250 335 -58 ;
199
+ C 169 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
200
+ C -1 ; WX 600 ; N Emacron ; B 53 0 550 698 ;
201
+ C -1 ; WX 600 ; N ccaron ; B 66 -15 529 669 ;
202
+ C 229 ; WX 600 ; N aring ; B 53 -15 559 627 ;
203
+ C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 593 562 ;
204
+ C -1 ; WX 600 ; N lacute ; B 95 0 505 805 ;
205
+ C 224 ; WX 600 ; N agrave ; B 53 -15 559 672 ;
206
+ C -1 ; WX 600 ; N Tcommaaccent ; B 38 -250 563 562 ;
207
+ C -1 ; WX 600 ; N Cacute ; B 41 -18 540 805 ;
208
+ C 227 ; WX 600 ; N atilde ; B 53 -15 559 606 ;
209
+ C -1 ; WX 600 ; N Edotaccent ; B 53 0 550 753 ;
210
+ C 154 ; WX 600 ; N scaron ; B 80 -15 513 669 ;
211
+ C -1 ; WX 600 ; N scedilla ; B 80 -151 513 441 ;
212
+ C 237 ; WX 600 ; N iacute ; B 95 0 505 672 ;
213
+ C -1 ; WX 600 ; N lozenge ; B 18 0 443 706 ;
214
+ C -1 ; WX 600 ; N Rcaron ; B 38 0 588 802 ;
215
+ C -1 ; WX 600 ; N Gcommaaccent ; B 31 -250 575 580 ;
216
+ C 251 ; WX 600 ; N ucircumflex ; B 21 -15 562 654 ;
217
+ C 226 ; WX 600 ; N acircumflex ; B 53 -15 559 654 ;
218
+ C -1 ; WX 600 ; N Amacron ; B 3 0 597 698 ;
219
+ C -1 ; WX 600 ; N rcaron ; B 60 0 559 669 ;
220
+ C 231 ; WX 600 ; N ccedilla ; B 66 -151 529 441 ;
221
+ C -1 ; WX 600 ; N Zdotaccent ; B 86 0 514 753 ;
222
+ C 222 ; WX 600 ; N Thorn ; B 79 0 538 562 ;
223
+ C -1 ; WX 600 ; N Omacron ; B 43 -18 557 698 ;
224
+ C -1 ; WX 600 ; N Racute ; B 38 0 588 805 ;
225
+ C -1 ; WX 600 ; N Sacute ; B 72 -20 529 805 ;
226
+ C -1 ; WX 600 ; N dcaron ; B 45 -15 715 629 ;
227
+ C -1 ; WX 600 ; N Umacron ; B 17 -18 583 698 ;
228
+ C -1 ; WX 600 ; N uring ; B 21 -15 562 627 ;
229
+ C 179 ; WX 600 ; N threesuperior ; B 155 240 406 622 ;
230
+ C 210 ; WX 600 ; N Ograve ; B 43 -18 557 805 ;
231
+ C 192 ; WX 600 ; N Agrave ; B 3 0 597 805 ;
232
+ C -1 ; WX 600 ; N Abreve ; B 3 0 597 732 ;
233
+ C 215 ; WX 600 ; N multiply ; B 87 43 515 470 ;
234
+ C 250 ; WX 600 ; N uacute ; B 21 -15 562 672 ;
235
+ C -1 ; WX 600 ; N Tcaron ; B 38 0 563 802 ;
236
+ C -1 ; WX 600 ; N partialdiff ; B 17 -38 459 710 ;
237
+ C 255 ; WX 600 ; N ydieresis ; B 7 -157 592 620 ;
238
+ C -1 ; WX 600 ; N Nacute ; B 7 -13 593 805 ;
239
+ C 238 ; WX 600 ; N icircumflex ; B 94 0 505 654 ;
240
+ C 202 ; WX 600 ; N Ecircumflex ; B 53 0 550 787 ;
241
+ C 228 ; WX 600 ; N adieresis ; B 53 -15 559 620 ;
242
+ C 235 ; WX 600 ; N edieresis ; B 66 -15 548 620 ;
243
+ C -1 ; WX 600 ; N cacute ; B 66 -15 529 672 ;
244
+ C -1 ; WX 600 ; N nacute ; B 26 0 575 672 ;
245
+ C -1 ; WX 600 ; N umacron ; B 21 -15 562 565 ;
246
+ C -1 ; WX 600 ; N Ncaron ; B 7 -13 593 802 ;
247
+ C 205 ; WX 600 ; N Iacute ; B 96 0 504 805 ;
248
+ C 177 ; WX 600 ; N plusminus ; B 87 44 513 558 ;
249
+ C 166 ; WX 600 ; N brokenbar ; B 275 -175 326 675 ;
250
+ C 174 ; WX 600 ; N registered ; B 0 -18 600 580 ;
251
+ C -1 ; WX 600 ; N Gbreve ; B 31 -18 575 732 ;
252
+ C -1 ; WX 600 ; N Idotaccent ; B 96 0 504 753 ;
253
+ C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ;
254
+ C 200 ; WX 600 ; N Egrave ; B 53 0 550 805 ;
255
+ C -1 ; WX 600 ; N racute ; B 60 0 559 672 ;
256
+ C -1 ; WX 600 ; N omacron ; B 62 -15 538 565 ;
257
+ C -1 ; WX 600 ; N Zacute ; B 86 0 514 805 ;
258
+ C 142 ; WX 600 ; N Zcaron ; B 86 0 514 802 ;
259
+ C -1 ; WX 600 ; N greaterequal ; B 98 0 502 710 ;
260
+ C 208 ; WX 600 ; N Eth ; B 30 0 574 562 ;
261
+ C 199 ; WX 600 ; N Ccedilla ; B 41 -151 540 580 ;
262
+ C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 505 629 ;
263
+ C -1 ; WX 600 ; N tcaron ; B 87 -15 530 717 ;
264
+ C -1 ; WX 600 ; N eogonek ; B 66 -172 548 441 ;
265
+ C -1 ; WX 600 ; N Uogonek ; B 17 -172 583 562 ;
266
+ C 193 ; WX 600 ; N Aacute ; B 3 0 597 805 ;
267
+ C 196 ; WX 600 ; N Adieresis ; B 3 0 597 753 ;
268
+ C 232 ; WX 600 ; N egrave ; B 66 -15 548 672 ;
269
+ C -1 ; WX 600 ; N zacute ; B 99 0 502 672 ;
270
+ C -1 ; WX 600 ; N iogonek ; B 95 -172 505 657 ;
271
+ C 211 ; WX 600 ; N Oacute ; B 43 -18 557 805 ;
272
+ C 243 ; WX 600 ; N oacute ; B 62 -15 538 672 ;
273
+ C -1 ; WX 600 ; N amacron ; B 53 -15 559 565 ;
274
+ C -1 ; WX 600 ; N sacute ; B 80 -15 513 672 ;
275
+ C 239 ; WX 600 ; N idieresis ; B 95 0 505 620 ;
276
+ C 212 ; WX 600 ; N Ocircumflex ; B 43 -18 557 787 ;
277
+ C 217 ; WX 600 ; N Ugrave ; B 17 -18 583 805 ;
278
+ C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
279
+ C 254 ; WX 600 ; N thorn ; B -6 -157 555 629 ;
280
+ C 178 ; WX 600 ; N twosuperior ; B 177 249 424 622 ;
281
+ C 214 ; WX 600 ; N Odieresis ; B 43 -18 557 753 ;
282
+ C 181 ; WX 600 ; N mu ; B 21 -157 562 426 ;
283
+ C 236 ; WX 600 ; N igrave ; B 95 0 505 672 ;
284
+ C -1 ; WX 600 ; N ohungarumlaut ; B 62 -15 580 672 ;
285
+ C -1 ; WX 600 ; N Eogonek ; B 53 -172 561 562 ;
286
+ C -1 ; WX 600 ; N dcroat ; B 45 -15 591 629 ;
287
+ C 190 ; WX 600 ; N threequarters ; B 8 -56 593 666 ;
288
+ C -1 ; WX 600 ; N Scedilla ; B 72 -151 529 580 ;
289
+ C -1 ; WX 600 ; N lcaron ; B 95 0 533 629 ;
290
+ C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 582 562 ;
291
+ C -1 ; WX 600 ; N Lacute ; B 47 0 554 805 ;
292
+ C 153 ; WX 600 ; N trademark ; B -23 263 623 562 ;
293
+ C -1 ; WX 600 ; N edotaccent ; B 66 -15 548 620 ;
294
+ C 204 ; WX 600 ; N Igrave ; B 96 0 504 805 ;
295
+ C -1 ; WX 600 ; N Imacron ; B 96 0 504 698 ;
296
+ C -1 ; WX 600 ; N Lcaron ; B 47 0 554 562 ;
297
+ C 189 ; WX 600 ; N onehalf ; B 0 -57 611 665 ;
298
+ C -1 ; WX 600 ; N lessequal ; B 98 0 502 710 ;
299
+ C 244 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ;
300
+ C 241 ; WX 600 ; N ntilde ; B 26 0 575 606 ;
301
+ C -1 ; WX 600 ; N Uhungarumlaut ; B 17 -18 590 805 ;
302
+ C 201 ; WX 600 ; N Eacute ; B 53 0 550 805 ;
303
+ C -1 ; WX 600 ; N emacron ; B 66 -15 548 565 ;
304
+ C -1 ; WX 600 ; N gbreve ; B 45 -157 566 609 ;
305
+ C 188 ; WX 600 ; N onequarter ; B 0 -57 600 665 ;
306
+ C 138 ; WX 600 ; N Scaron ; B 72 -20 529 802 ;
307
+ C -1 ; WX 600 ; N Scommaaccent ; B 72 -250 529 580 ;
308
+ C -1 ; WX 600 ; N Ohungarumlaut ; B 43 -18 580 805 ;
309
+ C 176 ; WX 600 ; N degree ; B 123 269 477 622 ;
310
+ C 242 ; WX 600 ; N ograve ; B 62 -15 538 672 ;
311
+ C -1 ; WX 600 ; N Ccaron ; B 41 -18 540 802 ;
312
+ C 249 ; WX 600 ; N ugrave ; B 21 -15 562 672 ;
313
+ C -1 ; WX 600 ; N radical ; B 3 -15 597 792 ;
314
+ C -1 ; WX 600 ; N Dcaron ; B 43 0 574 802 ;
315
+ C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 559 441 ;
316
+ C 209 ; WX 600 ; N Ntilde ; B 7 -13 593 729 ;
317
+ C 245 ; WX 600 ; N otilde ; B 62 -15 538 606 ;
318
+ C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 588 562 ;
319
+ C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 554 562 ;
320
+ C 195 ; WX 600 ; N Atilde ; B 3 0 597 729 ;
321
+ C -1 ; WX 600 ; N Aogonek ; B 3 -172 608 562 ;
322
+ C 197 ; WX 600 ; N Aring ; B 3 0 597 750 ;
323
+ C 213 ; WX 600 ; N Otilde ; B 43 -18 557 729 ;
324
+ C -1 ; WX 600 ; N zdotaccent ; B 99 0 502 620 ;
325
+ C -1 ; WX 600 ; N Ecaron ; B 53 0 550 802 ;
326
+ C -1 ; WX 600 ; N Iogonek ; B 96 -172 504 562 ;
327
+ C -1 ; WX 600 ; N kcommaaccent ; B 43 -250 580 629 ;
328
+ C -1 ; WX 600 ; N minus ; B 80 232 520 283 ;
329
+ C 206 ; WX 600 ; N Icircumflex ; B 96 0 504 787 ;
330
+ C -1 ; WX 600 ; N ncaron ; B 26 0 575 669 ;
331
+ C -1 ; WX 600 ; N tcommaaccent ; B 87 -250 530 561 ;
332
+ C 172 ; WX 600 ; N logicalnot ; B 87 108 513 369 ;
333
+ C 246 ; WX 600 ; N odieresis ; B 62 -15 538 620 ;
334
+ C 252 ; WX 600 ; N udieresis ; B 21 -15 562 620 ;
335
+ C -1 ; WX 600 ; N notequal ; B 15 -16 540 529 ;
336
+ C -1 ; WX 600 ; N gcommaaccent ; B 45 -157 566 708 ;
337
+ C 240 ; WX 600 ; N eth ; B 62 -15 538 629 ;
338
+ C 158 ; WX 600 ; N zcaron ; B 99 0 502 669 ;
339
+ C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 575 441 ;
340
+ C 185 ; WX 600 ; N onesuperior ; B 172 249 428 622 ;
341
+ C -1 ; WX 600 ; N imacron ; B 95 0 505 565 ;
342
+ C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
343
+ EndCharMetrics
344
+ EndFontMetrics
dompdf/lib/fonts/DejaVuSans-Bold.ttf ADDED
Binary file
dompdf/lib/fonts/DejaVuSans-Bold.ufm ADDED
@@ -0,0 +1,5199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ StartFontMetrics 4.1
2
+ FontName DejaVuSans-Bold
3
+ FullName DejaVu Sans Bold
4
+ Notice Converted by DOMPDF
5
+ EncodingScheme FontSpecific
6
+ FamilyName DejaVu Sans
7
+ Weight Bold
8
+ Version 65536
9
+ Characters
10
+ ItalicAngle 0
11
+ Ascender 928.22265625
12
+ Descender -235.83984375
13
+ UnderlineThickness 43.9453125
14
+ IsFixedPitch false
15
+ FontBBox -1069 -415 1975 1174
16
+ StemV 165
17
+ StartCharMetrics 5180
18
+ U 0 ; WX 5395 ; N uni0000 ; G 0
19
+ U 32 ; WX 348 ; N uni0020 ; G 3
20
+ U 33 ; WX 456 ; N uni0021 ; G 4
21
+ U 34 ; WX 521 ; N uni0022 ; G 5
22
+ U 35 ; WX 838 ; N uni0023 ; G 6
23
+ U 36 ; WX 696 ; N uni0024 ; G 7
24
+ U 37 ; WX 1002 ; N uni0025 ; G 8
25
+ U 38 ; WX 872 ; N uni0026 ; G 9
26
+ U 39 ; WX 306 ; N uni0027 ; G 10
27
+ U 40 ; WX 457 ; N uni0028 ; G 11
28
+ U 41 ; WX 457 ; N uni0029 ; G 12
29
+ U 42 ; WX 523 ; N uni002a ; G 13
30
+ U 43 ; WX 838 ; N uni002b ; G 14
31
+ U 44 ; WX 380 ; N uni002c ; G 15
32
+ U 45 ; WX 415 ; N uni002d ; G 16
33
+ U 46 ; WX 380 ; N uni002e ; G 17
34
+ U 47 ; WX 365 ; N uni002f ; G 18
35
+ U 48 ; WX 696 ; N uni0030 ; G 19
36
+ U 49 ; WX 696 ; N uni0031 ; G 20
37
+ U 50 ; WX 696 ; N uni0032 ; G 21
38
+ U 51 ; WX 696 ; N uni0033 ; G 22
39
+ U 52 ; WX 696 ; N uni0034 ; G 23
40
+ U 53 ; WX 696 ; N uni0035 ; G 24
41
+ U 54 ; WX 696 ; N uni0036 ; G 25
42
+ U 55 ; WX 696 ; N uni0037 ; G 26
43
+ U 56 ; WX 696 ; N uni0038 ; G 27
44
+ U 57 ; WX 696 ; N uni0039 ; G 28
45
+ U 58 ; WX 400 ; N uni003a ; G 29
46
+ U 59 ; WX 400 ; N uni003b ; G 30
47
+ U 60 ; WX 838 ; N uni003c ; G 31
48
+ U 61 ; WX 838 ; N uni003d ; G 32
49
+ U 62 ; WX 838 ; N uni003e ; G 33
50
+ U 63 ; WX 580 ; N uni003f ; G 34
51
+ U 64 ; WX 1000 ; N uni0040 ; G 35
52
+ U 65 ; WX 774 ; N uni0041 ; G 36
53
+ U 66 ; WX 762 ; N uni0042 ; G 37
54
+ U 67 ; WX 734 ; N uni0043 ; G 38
55
+ U 68 ; WX 830 ; N uni0044 ; G 39
56
+ U 69 ; WX 683 ; N uni0045 ; G 40
57
+ U 70 ; WX 683 ; N uni0046 ; G 41
58
+ U 71 ; WX 821 ; N uni0047 ; G 42
59
+ U 72 ; WX 837 ; N uni0048 ; G 43
60
+ U 73 ; WX 372 ; N uni0049 ; G 44
61
+ U 74 ; WX 372 ; N uni004a ; G 45
62
+ U 75 ; WX 775 ; N uni004b ; G 46
63
+ U 76 ; WX 637 ; N uni004c ; G 47
64
+ U 77 ; WX 995 ; N uni004d ; G 48
65
+ U 78 ; WX 837 ; N uni004e ; G 49
66
+ U 79 ; WX 850 ; N uni004f ; G 50
67
+ U 80 ; WX 733 ; N uni0050 ; G 51
68
+ U 81 ; WX 850 ; N uni0051 ; G 52
69
+ U 82 ; WX 770 ; N uni0052 ; G 53
70
+ U 83 ; WX 720 ; N uni0053 ; G 54
71
+ U 84 ; WX 682 ; N uni0054 ; G 55
72
+ U 85 ; WX 812 ; N uni0055 ; G 56
73
+ U 86 ; WX 774 ; N uni0056 ; G 57
74
+ U 87 ; WX 1103 ; N uni0057 ; G 58
75
+ U 88 ; WX 771 ; N uni0058 ; G 59
76
+ U 89 ; WX 724 ; N uni0059 ; G 60
77
+ U 90 ; WX 725 ; N uni005a ; G 61
78
+ U 91 ; WX 457 ; N uni005b ; G 62
79
+ U 92 ; WX 365 ; N uni005c ; G 63
80
+ U 93 ; WX 457 ; N uni005d ; G 64
81
+ U 94 ; WX 838 ; N uni005e ; G 65
82
+ U 95 ; WX 500 ; N uni005f ; G 66
83
+ U 96 ; WX 500 ; N uni0060 ; G 67
84
+ U 97 ; WX 675 ; N uni0061 ; G 68
85
+ U 98 ; WX 716 ; N uni0062 ; G 69
86
+ U 99 ; WX 593 ; N uni0063 ; G 70
87
+ U 100 ; WX 716 ; N uni0064 ; G 71
88
+ U 101 ; WX 678 ; N uni0065 ; G 72
89
+ U 102 ; WX 435 ; N uni0066 ; G 73
90
+ U 103 ; WX 716 ; N uni0067 ; G 74
91
+ U 104 ; WX 712 ; N uni0068 ; G 75
92
+ U 105 ; WX 343 ; N uni0069 ; G 76
93
+ U 106 ; WX 343 ; N uni006a ; G 77
94
+ U 107 ; WX 665 ; N uni006b ; G 78
95
+ U 108 ; WX 343 ; N uni006c ; G 79
96
+ U 109 ; WX 1042 ; N uni006d ; G 80
97
+ U 110 ; WX 712 ; N uni006e ; G 81
98
+ U 111 ; WX 687 ; N uni006f ; G 82
99
+ U 112 ; WX 716 ; N uni0070 ; G 83
100
+ U 113 ; WX 716 ; N uni0071 ; G 84
101
+ U 114 ; WX 493 ; N uni0072 ; G 85
102
+ U 115 ; WX 595 ; N uni0073 ; G 86
103
+ U 116 ; WX 478 ; N uni0074 ; G 87
104
+ U 117 ; WX 712 ; N uni0075 ; G 88
105
+ U 118 ; WX 652 ; N uni0076 ; G 89
106
+ U 119 ; WX 924 ; N uni0077 ; G 90
107
+ U 120 ; WX 645 ; N uni0078 ; G 91
108
+ U 121 ; WX 652 ; N uni0079 ; G 92
109
+ U 122 ; WX 582 ; N uni007a ; G 93
110
+ U 123 ; WX 712 ; N uni007b ; G 94
111
+ U 124 ; WX 365 ; N uni007c ; G 95
112
+ U 125 ; WX 712 ; N uni007d ; G 96
113
+ U 126 ; WX 838 ; N uni007e ; G 97
114
+ U 160 ; WX 348 ; N uni00a0 ; G 98
115
+ U 161 ; WX 456 ; N uni00a1 ; G 99
116
+ U 162 ; WX 696 ; N uni00a2 ; G 100
117
+ U 163 ; WX 696 ; N uni00a3 ; G 101
118
+ U 164 ; WX 636 ; N uni00a4 ; G 102
119
+ U 165 ; WX 696 ; N uni00a5 ; G 103
120
+ U 166 ; WX 365 ; N uni00a6 ; G 104
121
+ U 167 ; WX 500 ; N uni00a7 ; G 105
122
+ U 168 ; WX 500 ; N uni00a8 ; G 106
123
+ U 169 ; WX 1000 ; N uni00a9 ; G 107
124
+ U 170 ; WX 564 ; N uni00aa ; G 108
125
+ U 171 ; WX 646 ; N uni00ab ; G 109
126
+ U 172 ; WX 838 ; N uni00ac ; G 110
127
+ U 173 ; WX 415 ; N uni00ad ; G 111
128
+ U 174 ; WX 1000 ; N uni00ae ; G 112
129
+ U 175 ; WX 500 ; N uni00af ; G 113
130
+ U 176 ; WX 500 ; N uni00b0 ; G 114
131
+ U 177 ; WX 838 ; N uni00b1 ; G 115
132
+ U 178 ; WX 438 ; N uni00b2 ; G 116
133
+ U 179 ; WX 438 ; N uni00b3 ; G 117
134
+ U 180 ; WX 500 ; N uni00b4 ; G 118
135
+ U 181 ; WX 736 ; N uni00b5 ; G 119
136
+ U 182 ; WX 636 ; N uni00b6 ; G 120
137
+ U 183 ; WX 380 ; N uni00b7 ; G 121
138
+ U 184 ; WX 500 ; N uni00b8 ; G 122
139
+ U 185 ; WX 438 ; N uni00b9 ; G 123
140
+ U 186 ; WX 564 ; N uni00ba ; G 124
141
+ U 187 ; WX 646 ; N uni00bb ; G 125
142
+ U 188 ; WX 1035 ; N uni00bc ; G 126
143
+ U 189 ; WX 1035 ; N uni00bd ; G 127
144
+ U 190 ; WX 1035 ; N uni00be ; G 128
145
+ U 191 ; WX 580 ; N uni00bf ; G 129
146
+ U 192 ; WX 774 ; N uni00c0 ; G 130
147
+ U 193 ; WX 774 ; N uni00c1 ; G 131
148
+ U 194 ; WX 774 ; N uni00c2 ; G 132
149
+ U 195 ; WX 774 ; N uni00c3 ; G 133
150
+ U 196 ; WX 774 ; N uni00c4 ; G 134
151
+ U 197 ; WX 774 ; N uni00c5 ; G 135
152
+ U 198 ; WX 1085 ; N uni00c6 ; G 136
153
+ U 199 ; WX 734 ; N uni00c7 ; G 137
154
+ U 200 ; WX 683 ; N uni00c8 ; G 138
155
+ U 201 ; WX 683 ; N uni00c9 ; G 139
156
+ U 202 ; WX 683 ; N uni00ca ; G 140
157
+ U 203 ; WX 683 ; N uni00cb ; G 141
158
+ U 204 ; WX 372 ; N uni00cc ; G 142
159
+ U 205 ; WX 372 ; N uni00cd ; G 143
160
+ U 206 ; WX 372 ; N uni00ce ; G 144
161
+ U 207 ; WX 372 ; N uni00cf ; G 145
162
+ U 208 ; WX 838 ; N uni00d0 ; G 146
163
+ U 209 ; WX 837 ; N uni00d1 ; G 147
164
+ U 210 ; WX 850 ; N uni00d2 ; G 148
165
+ U 211 ; WX 850 ; N uni00d3 ; G 149
166
+ U 212 ; WX 850 ; N uni00d4 ; G 150
167
+ U 213 ; WX 850 ; N uni00d5 ; G 151
168
+ U 214 ; WX 850 ; N uni00d6 ; G 152
169
+ U 215 ; WX 838 ; N uni00d7 ; G 153
170
+ U 216 ; WX 850 ; N uni00d8 ; G 154
171
+ U 217 ; WX 812 ; N uni00d9 ; G 155
172
+ U 218 ; WX 812 ; N uni00da ; G 156
173
+ U 219 ; WX 812 ; N uni00db ; G 157
174
+ U 220 ; WX 812 ; N uni00dc ; G 158
175
+ U 221 ; WX 724 ; N uni00dd ; G 159
176
+ U 222 ; WX 738 ; N uni00de ; G 160
177
+ U 223 ; WX 719 ; N uni00df ; G 161
178
+ U 224 ; WX 675 ; N uni00e0 ; G 162
179
+ U 225 ; WX 675 ; N uni00e1 ; G 163
180
+ U 226 ; WX 675 ; N uni00e2 ; G 164
181
+ U 227 ; WX 675 ; N uni00e3 ; G 165
182
+ U 228 ; WX 675 ; N uni00e4 ; G 166
183
+ U 229 ; WX 675 ; N uni00e5 ; G 167
184
+ U 230 ; WX 1048 ; N uni00e6 ; G 168
185
+ U 231 ; WX 593 ; N uni00e7 ; G 169
186
+ U 232 ; WX 678 ; N uni00e8 ; G 170
187
+ U 233 ; WX 678 ; N uni00e9 ; G 171
188
+ U 234 ; WX 678 ; N uni00ea ; G 172
189
+ U 235 ; WX 678 ; N uni00eb ; G 173
190
+ U 236 ; WX 343 ; N uni00ec ; G 174
191
+ U 237 ; WX 343 ; N uni00ed ; G 175
192
+ U 238 ; WX 343 ; N uni00ee ; G 176
193
+ U 239 ; WX 343 ; N uni00ef ; G 177
194
+ U 240 ; WX 687 ; N uni00f0 ; G 178
195
+ U 241 ; WX 712 ; N uni00f1 ; G 179
196
+ U 242 ; WX 687 ; N uni00f2 ; G 180
197
+ U 243 ; WX 687 ; N uni00f3 ; G 181
198
+ U 244 ; WX 687 ; N uni00f4 ; G 182
199
+ U 245 ; WX 687 ; N uni00f5 ; G 183
200
+ U 246 ; WX 687 ; N uni00f6 ; G 184
201
+ U 247 ; WX 838 ; N uni00f7 ; G 185
202
+ U 248 ; WX 687 ; N uni00f8 ; G 186
203
+ U 249 ; WX 712 ; N uni00f9 ; G 187
204
+ U 250 ; WX 712 ; N uni00fa ; G 188
205
+ U 251 ; WX 712 ; N uni00fb ; G 189
206
+ U 252 ; WX 712 ; N uni00fc ; G 190
207
+ U 253 ; WX 652 ; N uni00fd ; G 191
208
+ U 254 ; WX 716 ; N uni00fe ; G 192
209
+ U 255 ; WX 652 ; N uni00ff ; G 193
210
+ U 256 ; WX 774 ; N uni0100 ; G 194
211
+ U 257 ; WX 675 ; N uni0101 ; G 195
212
+ U 258 ; WX 774 ; N uni0102 ; G 196
213
+ U 259 ; WX 675 ; N uni0103 ; G 197
214
+ U 260 ; WX 774 ; N uni0104 ; G 198
215
+ U 261 ; WX 675 ; N uni0105 ; G 199
216
+ U 262 ; WX 734 ; N uni0106 ; G 200
217
+ U 263 ; WX 593 ; N uni0107 ; G 201
218
+ U 264 ; WX 734 ; N uni0108 ; G 202
219
+ U 265 ; WX 593 ; N uni0109 ; G 203
220
+ U 266 ; WX 734 ; N uni010a ; G 204
221
+ U 267 ; WX 593 ; N uni010b ; G 205
222
+ U 268 ; WX 734 ; N uni010c ; G 206
223
+ U 269 ; WX 593 ; N uni010d ; G 207
224
+ U 270 ; WX 830 ; N uni010e ; G 208
225
+ U 271 ; WX 716 ; N uni010f ; G 209
226
+ U 272 ; WX 838 ; N uni0110 ; G 210
227
+ U 273 ; WX 716 ; N uni0111 ; G 211
228
+ U 274 ; WX 683 ; N uni0112 ; G 212
229
+ U 275 ; WX 678 ; N uni0113 ; G 213
230
+ U 276 ; WX 683 ; N uni0114 ; G 214
231
+ U 277 ; WX 678 ; N uni0115 ; G 215
232
+ U 278 ; WX 683 ; N uni0116 ; G 216
233
+ U 279 ; WX 678 ; N uni0117 ; G 217
234
+ U 280 ; WX 683 ; N uni0118 ; G 218
235
+ U 281 ; WX 678 ; N uni0119 ; G 219
236
+ U 282 ; WX 683 ; N uni011a ; G 220
237
+ U 283 ; WX 678 ; N uni011b ; G 221
238
+ U 284 ; WX 821 ; N uni011c ; G 222
239
+ U 285 ; WX 716 ; N uni011d ; G 223
240
+ U 286 ; WX 821 ; N uni011e ; G 224
241
+ U 287 ; WX 716 ; N uni011f ; G 225
242
+ U 288 ; WX 821 ; N uni0120 ; G 226
243
+ U 289 ; WX 716 ; N uni0121 ; G 227
244
+ U 290 ; WX 821 ; N uni0122 ; G 228
245
+ U 291 ; WX 716 ; N uni0123 ; G 229
246
+ U 292 ; WX 837 ; N uni0124 ; G 230
247
+ U 293 ; WX 712 ; N uni0125 ; G 231
248
+ U 294 ; WX 974 ; N uni0126 ; G 232
249
+ U 295 ; WX 790 ; N uni0127 ; G 233
250
+ U 296 ; WX 372 ; N uni0128 ; G 234
251
+ U 297 ; WX 343 ; N uni0129 ; G 235
252
+ U 298 ; WX 372 ; N uni012a ; G 236
253
+ U 299 ; WX 343 ; N uni012b ; G 237
254
+ U 300 ; WX 372 ; N uni012c ; G 238
255
+ U 301 ; WX 343 ; N uni012d ; G 239
256
+ U 302 ; WX 372 ; N uni012e ; G 240
257
+ U 303 ; WX 343 ; N uni012f ; G 241
258
+ U 304 ; WX 372 ; N uni0130 ; G 242
259
+ U 305 ; WX 343 ; N uni0131 ; G 243
260
+ U 306 ; WX 744 ; N uni0132 ; G 244
261
+ U 307 ; WX 686 ; N uni0133 ; G 245
262
+ U 308 ; WX 372 ; N uni0134 ; G 246
263
+ U 309 ; WX 343 ; N uni0135 ; G 247
264
+ U 310 ; WX 775 ; N uni0136 ; G 248
265
+ U 311 ; WX 665 ; N uni0137 ; G 249
266
+ U 312 ; WX 665 ; N uni0138 ; G 250
267
+ U 313 ; WX 637 ; N uni0139 ; G 251
268
+ U 314 ; WX 343 ; N uni013a ; G 252
269
+ U 315 ; WX 637 ; N uni013b ; G 253
270
+ U 316 ; WX 343 ; N uni013c ; G 254
271
+ U 317 ; WX 637 ; N uni013d ; G 255
272
+ U 318 ; WX 479 ; N uni013e ; G 256
273
+ U 319 ; WX 637 ; N uni013f ; G 257
274
+ U 320 ; WX 557 ; N uni0140 ; G 258
275
+ U 321 ; WX 642 ; N uni0141 ; G 259
276
+ U 322 ; WX 371 ; N uni0142 ; G 260
277
+ U 323 ; WX 837 ; N uni0143 ; G 261
278
+ U 324 ; WX 712 ; N uni0144 ; G 262
279
+ U 325 ; WX 837 ; N uni0145 ; G 263
280
+ U 326 ; WX 712 ; N uni0146 ; G 264
281
+ U 327 ; WX 837 ; N uni0147 ; G 265
282
+ U 328 ; WX 712 ; N uni0148 ; G 266
283
+ U 329 ; WX 983 ; N uni0149 ; G 267
284
+ U 330 ; WX 837 ; N uni014a ; G 268
285
+ U 331 ; WX 712 ; N uni014b ; G 269
286
+ U 332 ; WX 850 ; N uni014c ; G 270
287
+ U 333 ; WX 687 ; N uni014d ; G 271
288
+ U 334 ; WX 850 ; N uni014e ; G 272
289
+ U 335 ; WX 687 ; N uni014f ; G 273
290
+ U 336 ; WX 850 ; N uni0150 ; G 274
291
+ U 337 ; WX 687 ; N uni0151 ; G 275
292
+ U 338 ; WX 1167 ; N uni0152 ; G 276
293
+ U 339 ; WX 1094 ; N uni0153 ; G 277
294
+ U 340 ; WX 770 ; N uni0154 ; G 278
295
+ U 341 ; WX 493 ; N uni0155 ; G 279
296
+ U 342 ; WX 770 ; N uni0156 ; G 280
297
+ U 343 ; WX 493 ; N uni0157 ; G 281
298
+ U 344 ; WX 770 ; N uni0158 ; G 282
299
+ U 345 ; WX 493 ; N uni0159 ; G 283
300
+ U 346 ; WX 720 ; N uni015a ; G 284
301
+ U 347 ; WX 595 ; N uni015b ; G 285
302
+ U 348 ; WX 720 ; N uni015c ; G 286
303
+ U 349 ; WX 595 ; N uni015d ; G 287
304
+ U 350 ; WX 720 ; N uni015e ; G 288
305
+ U 351 ; WX 595 ; N uni015f ; G 289
306
+ U 352 ; WX 720 ; N uni0160 ; G 290
307
+ U 353 ; WX 595 ; N uni0161 ; G 291
308
+ U 354 ; WX 682 ; N uni0162 ; G 292
309
+ U 355 ; WX 478 ; N uni0163 ; G 293
310
+ U 356 ; WX 682 ; N uni0164 ; G 294
311
+ U 357 ; WX 478 ; N uni0165 ; G 295
312
+ U 358 ; WX 682 ; N uni0166 ; G 296
313
+ U 359 ; WX 478 ; N uni0167 ; G 297
314
+ U 360 ; WX 812 ; N uni0168 ; G 298
315
+ U 361 ; WX 712 ; N uni0169 ; G 299
316
+ U 362 ; WX 812 ; N uni016a ; G 300
317
+ U 363 ; WX 712 ; N uni016b ; G 301
318
+ U 364 ; WX 812 ; N uni016c ; G 302
319
+ U 365 ; WX 712 ; N uni016d ; G 303
320
+ U 366 ; WX 812 ; N uni016e ; G 304
321
+ U 367 ; WX 712 ; N uni016f ; G 305
322
+ U 368 ; WX 812 ; N uni0170 ; G 306
323
+ U 369 ; WX 712 ; N uni0171 ; G 307
324
+ U 370 ; WX 812 ; N uni0172 ; G 308
325
+ U 371 ; WX 712 ; N uni0173 ; G 309
326
+ U 372 ; WX 1103 ; N uni0174 ; G 310
327
+ U 373 ; WX 924 ; N uni0175 ; G 311
328
+ U 374 ; WX 724 ; N uni0176 ; G 312
329
+ U 375 ; WX 652 ; N uni0177 ; G 313
330
+ U 376 ; WX 724 ; N uni0178 ; G 314
331
+ U 377 ; WX 725 ; N uni0179 ; G 315
332
+ U 378 ; WX 582 ; N uni017a ; G 316
333
+ U 379 ; WX 725 ; N uni017b ; G 317
334
+ U 380 ; WX 582 ; N uni017c ; G 318
335
+ U 381 ; WX 725 ; N uni017d ; G 319
336
+ U 382 ; WX 582 ; N uni017e ; G 320
337
+ U 383 ; WX 435 ; N uni017f ; G 321
338
+ U 384 ; WX 716 ; N uni0180 ; G 322
339
+ U 385 ; WX 811 ; N uni0181 ; G 323
340
+ U 386 ; WX 762 ; N uni0182 ; G 324
341
+ U 387 ; WX 716 ; N uni0183 ; G 325
342
+ U 388 ; WX 762 ; N uni0184 ; G 326
343
+ U 389 ; WX 716 ; N uni0185 ; G 327
344
+ U 390 ; WX 734 ; N uni0186 ; G 328
345
+ U 391 ; WX 734 ; N uni0187 ; G 329
346
+ U 392 ; WX 593 ; N uni0188 ; G 330
347
+ U 393 ; WX 838 ; N uni0189 ; G 331
348
+ U 394 ; WX 879 ; N uni018a ; G 332
349
+ U 395 ; WX 757 ; N uni018b ; G 333
350
+ U 396 ; WX 716 ; N uni018c ; G 334
351
+ U 397 ; WX 688 ; N uni018d ; G 335
352
+ U 398 ; WX 683 ; N uni018e ; G 336
353
+ U 399 ; WX 849 ; N uni018f ; G 337
354
+ U 400 ; WX 696 ; N uni0190 ; G 338
355
+ U 401 ; WX 683 ; N uni0191 ; G 339
356
+ U 402 ; WX 435 ; N uni0192 ; G 340
357
+ U 403 ; WX 821 ; N uni0193 ; G 341
358
+ U 404 ; WX 793 ; N uni0194 ; G 342
359
+ U 405 ; WX 1045 ; N uni0195 ; G 343
360
+ U 406 ; WX 436 ; N uni0196 ; G 344
361
+ U 407 ; WX 389 ; N uni0197 ; G 345
362
+ U 408 ; WX 775 ; N uni0198 ; G 346
363
+ U 409 ; WX 665 ; N uni0199 ; G 347
364
+ U 410 ; WX 360 ; N uni019a ; G 348
365
+ U 411 ; WX 592 ; N uni019b ; G 349
366
+ U 412 ; WX 1042 ; N uni019c ; G 350
367
+ U 413 ; WX 837 ; N uni019d ; G 351
368
+ U 414 ; WX 712 ; N uni019e ; G 352
369
+ U 415 ; WX 850 ; N uni019f ; G 353
370
+ U 416 ; WX 874 ; N uni01a0 ; G 354
371
+ U 417 ; WX 687 ; N uni01a1 ; G 355
372
+ U 418 ; WX 1083 ; N uni01a2 ; G 356
373
+ U 419 ; WX 912 ; N uni01a3 ; G 357
374
+ U 420 ; WX 782 ; N uni01a4 ; G 358
375
+ U 421 ; WX 716 ; N uni01a5 ; G 359
376
+ U 422 ; WX 770 ; N uni01a6 ; G 360
377
+ U 423 ; WX 720 ; N uni01a7 ; G 361
378
+ U 424 ; WX 595 ; N uni01a8 ; G 362
379
+ U 425 ; WX 683 ; N uni01a9 ; G 363
380
+ U 426 ; WX 552 ; N uni01aa ; G 364
381
+ U 427 ; WX 478 ; N uni01ab ; G 365
382
+ U 428 ; WX 707 ; N uni01ac ; G 366
383
+ U 429 ; WX 478 ; N uni01ad ; G 367
384
+ U 430 ; WX 682 ; N uni01ae ; G 368
385
+ U 431 ; WX 835 ; N uni01af ; G 369
386
+ U 432 ; WX 712 ; N uni01b0 ; G 370
387
+ U 433 ; WX 850 ; N uni01b1 ; G 371
388
+ U 434 ; WX 813 ; N uni01b2 ; G 372
389
+ U 435 ; WX 797 ; N uni01b3 ; G 373
390
+ U 436 ; WX 778 ; N uni01b4 ; G 374
391
+ U 437 ; WX 725 ; N uni01b5 ; G 375
392
+ U 438 ; WX 582 ; N uni01b6 ; G 376
393
+ U 439 ; WX 772 ; N uni01b7 ; G 377
394
+ U 440 ; WX 772 ; N uni01b8 ; G 378
395
+ U 441 ; WX 641 ; N uni01b9 ; G 379
396
+ U 442 ; WX 582 ; N uni01ba ; G 380
397
+ U 443 ; WX 696 ; N uni01bb ; G 381
398
+ U 444 ; WX 772 ; N uni01bc ; G 382
399
+ U 445 ; WX 641 ; N uni01bd ; G 383
400
+ U 446 ; WX 573 ; N uni01be ; G 384
401
+ U 447 ; WX 716 ; N uni01bf ; G 385
402
+ U 448 ; WX 372 ; N uni01c0 ; G 386
403
+ U 449 ; WX 659 ; N uni01c1 ; G 387
404
+ U 450 ; WX 544 ; N uni01c2 ; G 388
405
+ U 451 ; WX 372 ; N uni01c3 ; G 389
406
+ U 452 ; WX 1555 ; N uni01c4 ; G 390
407
+ U 453 ; WX 1412 ; N uni01c5 ; G 391
408
+ U 454 ; WX 1298 ; N uni01c6 ; G 392
409
+ U 455 ; WX 1009 ; N uni01c7 ; G 393
410
+ U 456 ; WX 980 ; N uni01c8 ; G 394
411
+ U 457 ; WX 686 ; N uni01c9 ; G 395
412
+ U 458 ; WX 1209 ; N uni01ca ; G 396
413
+ U 459 ; WX 1180 ; N uni01cb ; G 397
414
+ U 460 ; WX 1055 ; N uni01cc ; G 398
415
+ U 461 ; WX 774 ; N uni01cd ; G 399
416
+ U 462 ; WX 675 ; N uni01ce ; G 400
417
+ U 463 ; WX 372 ; N uni01cf ; G 401
418
+ U 464 ; WX 343 ; N uni01d0 ; G 402
419
+ U 465 ; WX 850 ; N uni01d1 ; G 403
420
+ U 466 ; WX 687 ; N uni01d2 ; G 404
421
+ U 467 ; WX 812 ; N uni01d3 ; G 405
422
+ U 468 ; WX 712 ; N uni01d4 ; G 406
423
+ U 469 ; WX 812 ; N uni01d5 ; G 407
424
+ U 470 ; WX 712 ; N uni01d6 ; G 408
425
+ U 471 ; WX 812 ; N uni01d7 ; G 409
426
+ U 472 ; WX 712 ; N uni01d8 ; G 410
427
+ U 473 ; WX 812 ; N uni01d9 ; G 411
428
+ U 474 ; WX 712 ; N uni01da ; G 412
429
+ U 475 ; WX 812 ; N uni01db ; G 413
430
+ U 476 ; WX 712 ; N uni01dc ; G 414
431
+ U 477 ; WX 678 ; N uni01dd ; G 415
432
+ U 478 ; WX 774 ; N uni01de ; G 416
433
+ U 479 ; WX 675 ; N uni01df ; G 417
434
+ U 480 ; WX 774 ; N uni01e0 ; G 418
435
+ U 481 ; WX 675 ; N uni01e1 ; G 419
436
+ U 482 ; WX 1085 ; N uni01e2 ; G 420
437
+ U 483 ; WX 1048 ; N uni01e3 ; G 421
438
+ U 484 ; WX 821 ; N uni01e4 ; G 422
439
+ U 485 ; WX 716 ; N uni01e5 ; G 423
440
+ U 486 ; WX 821 ; N uni01e6 ; G 424
441
+ U 487 ; WX 716 ; N uni01e7 ; G 425
442
+ U 488 ; WX 775 ; N uni01e8 ; G 426
443
+ U 489 ; WX 665 ; N uni01e9 ; G 427
444
+ U 490 ; WX 850 ; N uni01ea ; G 428
445
+ U 491 ; WX 687 ; N uni01eb ; G 429
446
+ U 492 ; WX 850 ; N uni01ec ; G 430
447
+ U 493 ; WX 687 ; N uni01ed ; G 431
448
+ U 494 ; WX 772 ; N uni01ee ; G 432
449
+ U 495 ; WX 582 ; N uni01ef ; G 433
450
+ U 496 ; WX 343 ; N uni01f0 ; G 434
451
+ U 497 ; WX 1555 ; N uni01f1 ; G 435
452
+ U 498 ; WX 1412 ; N uni01f2 ; G 436
453
+ U 499 ; WX 1298 ; N uni01f3 ; G 437
454
+ U 500 ; WX 821 ; N uni01f4 ; G 438
455
+ U 501 ; WX 716 ; N uni01f5 ; G 439
456
+ U 502 ; WX 1289 ; N uni01f6 ; G 440
457
+ U 503 ; WX 787 ; N uni01f7 ; G 441
458
+ U 504 ; WX 837 ; N uni01f8 ; G 442
459
+ U 505 ; WX 712 ; N uni01f9 ; G 443
460
+ U 506 ; WX 774 ; N uni01fa ; G 444
461
+ U 507 ; WX 675 ; N uni01fb ; G 445
462
+ U 508 ; WX 1085 ; N uni01fc ; G 446
463
+ U 509 ; WX 1048 ; N uni01fd ; G 447
464
+ U 510 ; WX 850 ; N uni01fe ; G 448
465
+ U 511 ; WX 687 ; N uni01ff ; G 449
466
+ U 512 ; WX 774 ; N uni0200 ; G 450
467
+ U 513 ; WX 675 ; N uni0201 ; G 451
468
+ U 514 ; WX 774 ; N uni0202 ; G 452
469
+ U 515 ; WX 675 ; N uni0203 ; G 453
470
+ U 516 ; WX 683 ; N uni0204 ; G 454
471
+ U 517 ; WX 678 ; N uni0205 ; G 455
472
+ U 518 ; WX 683 ; N uni0206 ; G 456
473
+ U 519 ; WX 678 ; N uni0207 ; G 457
474
+ U 520 ; WX 372 ; N uni0208 ; G 458
475
+ U 521 ; WX 343 ; N uni0209 ; G 459
476
+ U 522 ; WX 372 ; N uni020a ; G 460
477
+ U 523 ; WX 343 ; N uni020b ; G 461
478
+ U 524 ; WX 850 ; N uni020c ; G 462
479
+ U 525 ; WX 687 ; N uni020d ; G 463
480
+ U 526 ; WX 850 ; N uni020e ; G 464
481
+ U 527 ; WX 687 ; N uni020f ; G 465
482
+ U 528 ; WX 770 ; N uni0210 ; G 466
483
+ U 529 ; WX 493 ; N uni0211 ; G 467
484
+ U 530 ; WX 770 ; N uni0212 ; G 468
485
+ U 531 ; WX 493 ; N uni0213 ; G 469
486
+ U 532 ; WX 812 ; N uni0214 ; G 470
487
+ U 533 ; WX 712 ; N uni0215 ; G 471
488
+ U 534 ; WX 812 ; N uni0216 ; G 472
489
+ U 535 ; WX 712 ; N uni0217 ; G 473
490
+ U 536 ; WX 720 ; N uni0218 ; G 474
491
+ U 537 ; WX 595 ; N uni0219 ; G 475
492
+ U 538 ; WX 682 ; N uni021a ; G 476
493
+ U 539 ; WX 478 ; N uni021b ; G 477
494
+ U 540 ; WX 690 ; N uni021c ; G 478
495
+ U 541 ; WX 607 ; N uni021d ; G 479
496
+ U 542 ; WX 837 ; N uni021e ; G 480
497
+ U 543 ; WX 712 ; N uni021f ; G 481
498
+ U 544 ; WX 837 ; N uni0220 ; G 482
499
+ U 545 ; WX 865 ; N uni0221 ; G 483
500
+ U 546 ; WX 809 ; N uni0222 ; G 484
501
+ U 547 ; WX 659 ; N uni0223 ; G 485
502
+ U 548 ; WX 725 ; N uni0224 ; G 486
503
+ U 549 ; WX 582 ; N uni0225 ; G 487
504
+ U 550 ; WX 774 ; N uni0226 ; G 488
505
+ U 551 ; WX 675 ; N uni0227 ; G 489
506
+ U 552 ; WX 683 ; N uni0228 ; G 490
507
+ U 553 ; WX 678 ; N uni0229 ; G 491
508
+ U 554 ; WX 850 ; N uni022a ; G 492
509
+ U 555 ; WX 687 ; N uni022b ; G 493
510
+ U 556 ; WX 850 ; N uni022c ; G 494
511
+ U 557 ; WX 687 ; N uni022d ; G 495
512
+ U 558 ; WX 850 ; N uni022e ; G 496
513
+ U 559 ; WX 687 ; N uni022f ; G 497
514
+ U 560 ; WX 850 ; N uni0230 ; G 498
515
+ U 561 ; WX 687 ; N uni0231 ; G 499
516
+ U 562 ; WX 724 ; N uni0232 ; G 500
517
+ U 563 ; WX 652 ; N uni0233 ; G 501
518
+ U 564 ; WX 492 ; N uni0234 ; G 502
519
+ U 565 ; WX 867 ; N uni0235 ; G 503
520
+ U 566 ; WX 512 ; N uni0236 ; G 504
521
+ U 567 ; WX 343 ; N uni0237 ; G 505
522
+ U 568 ; WX 1088 ; N uni0238 ; G 506
523
+ U 569 ; WX 1088 ; N uni0239 ; G 507
524
+ U 570 ; WX 774 ; N uni023a ; G 508
525
+ U 571 ; WX 734 ; N uni023b ; G 509
526
+ U 572 ; WX 593 ; N uni023c ; G 510
527
+ U 573 ; WX 637 ; N uni023d ; G 511
528
+ U 574 ; WX 682 ; N uni023e ; G 512
529
+ U 575 ; WX 595 ; N uni023f ; G 513
530
+ U 576 ; WX 582 ; N uni0240 ; G 514
531
+ U 577 ; WX 782 ; N uni0241 ; G 515
532
+ U 578 ; WX 614 ; N uni0242 ; G 516
533
+ U 579 ; WX 762 ; N uni0243 ; G 517
534
+ U 580 ; WX 812 ; N uni0244 ; G 518
535
+ U 581 ; WX 774 ; N uni0245 ; G 519
536
+ U 582 ; WX 683 ; N uni0246 ; G 520
537
+ U 583 ; WX 678 ; N uni0247 ; G 521
538
+ U 584 ; WX 372 ; N uni0248 ; G 522
539
+ U 585 ; WX 343 ; N uni0249 ; G 523
540
+ U 586 ; WX 860 ; N uni024a ; G 524
541
+ U 587 ; WX 791 ; N uni024b ; G 525
542
+ U 588 ; WX 770 ; N uni024c ; G 526
543
+ U 589 ; WX 493 ; N uni024d ; G 527
544
+ U 590 ; WX 724 ; N uni024e ; G 528
545
+ U 591 ; WX 652 ; N uni024f ; G 529
546
+ U 592 ; WX 675 ; N uni0250 ; G 530
547
+ U 593 ; WX 716 ; N uni0251 ; G 531
548
+ U 594 ; WX 716 ; N uni0252 ; G 532
549
+ U 595 ; WX 716 ; N uni0253 ; G 533
550
+ U 596 ; WX 593 ; N uni0254 ; G 534
551
+ U 597 ; WX 593 ; N uni0255 ; G 535
552
+ U 598 ; WX 717 ; N uni0256 ; G 536
553
+ U 599 ; WX 792 ; N uni0257 ; G 537
554
+ U 600 ; WX 678 ; N uni0258 ; G 538
555
+ U 601 ; WX 678 ; N uni0259 ; G 539
556
+ U 602 ; WX 876 ; N uni025a ; G 540
557
+ U 603 ; WX 557 ; N uni025b ; G 541
558
+ U 604 ; WX 545 ; N uni025c ; G 542
559
+ U 605 ; WX 815 ; N uni025d ; G 543
560
+ U 606 ; WX 731 ; N uni025e ; G 544
561
+ U 607 ; WX 343 ; N uni025f ; G 545
562
+ U 608 ; WX 792 ; N uni0260 ; G 546
563
+ U 609 ; WX 716 ; N uni0261 ; G 547
564
+ U 610 ; WX 627 ; N uni0262 ; G 548
565
+ U 611 ; WX 644 ; N uni0263 ; G 549
566
+ U 612 ; WX 635 ; N uni0264 ; G 550
567
+ U 613 ; WX 712 ; N uni0265 ; G 551
568
+ U 614 ; WX 712 ; N uni0266 ; G 552
569
+ U 615 ; WX 712 ; N uni0267 ; G 553
570
+ U 616 ; WX 545 ; N uni0268 ; G 554
571
+ U 617 ; WX 440 ; N uni0269 ; G 555
572
+ U 618 ; WX 545 ; N uni026a ; G 556
573
+ U 619 ; WX 559 ; N uni026b ; G 557
574
+ U 620 ; WX 693 ; N uni026c ; G 558
575
+ U 621 ; WX 343 ; N uni026d ; G 559
576
+ U 622 ; WX 841 ; N uni026e ; G 560
577
+ U 623 ; WX 1042 ; N uni026f ; G 561
578
+ U 624 ; WX 1042 ; N uni0270 ; G 562
579
+ U 625 ; WX 1042 ; N uni0271 ; G 563
580
+ U 626 ; WX 712 ; N uni0272 ; G 564
581
+ U 627 ; WX 793 ; N uni0273 ; G 565
582
+ U 628 ; WX 707 ; N uni0274 ; G 566
583
+ U 629 ; WX 687 ; N uni0275 ; G 567
584
+ U 630 ; WX 909 ; N uni0276 ; G 568
585
+ U 631 ; WX 681 ; N uni0277 ; G 569
586
+ U 632 ; WX 796 ; N uni0278 ; G 570
587
+ U 633 ; WX 538 ; N uni0279 ; G 571
588
+ U 634 ; WX 538 ; N uni027a ; G 572
589
+ U 635 ; WX 650 ; N uni027b ; G 573
590
+ U 636 ; WX 493 ; N uni027c ; G 574
591
+ U 637 ; WX 493 ; N uni027d ; G 575
592
+ U 638 ; WX 596 ; N uni027e ; G 576
593
+ U 639 ; WX 596 ; N uni027f ; G 577
594
+ U 640 ; WX 642 ; N uni0280 ; G 578
595
+ U 641 ; WX 642 ; N uni0281 ; G 579
596
+ U 642 ; WX 595 ; N uni0282 ; G 580
597
+ U 643 ; WX 415 ; N uni0283 ; G 581
598
+ U 644 ; WX 435 ; N uni0284 ; G 582
599
+ U 645 ; WX 605 ; N uni0285 ; G 583
600
+ U 646 ; WX 552 ; N uni0286 ; G 584
601
+ U 647 ; WX 478 ; N uni0287 ; G 585
602
+ U 648 ; WX 478 ; N uni0288 ; G 586
603
+ U 649 ; WX 920 ; N uni0289 ; G 587
604
+ U 650 ; WX 772 ; N uni028a ; G 588
605
+ U 651 ; WX 670 ; N uni028b ; G 589
606
+ U 652 ; WX 652 ; N uni028c ; G 590
607
+ U 653 ; WX 924 ; N uni028d ; G 591
608
+ U 654 ; WX 652 ; N uni028e ; G 592
609
+ U 655 ; WX 724 ; N uni028f ; G 593
610
+ U 656 ; WX 694 ; N uni0290 ; G 594
611
+ U 657 ; WX 684 ; N uni0291 ; G 595
612
+ U 658 ; WX 641 ; N uni0292 ; G 596
613
+ U 659 ; WX 641 ; N uni0293 ; G 597
614
+ U 660 ; WX 573 ; N uni0294 ; G 598
615
+ U 661 ; WX 573 ; N uni0295 ; G 599
616
+ U 662 ; WX 573 ; N uni0296 ; G 600
617
+ U 663 ; WX 573 ; N uni0297 ; G 601
618
+ U 664 ; WX 850 ; N uni0298 ; G 602
619
+ U 665 ; WX 633 ; N uni0299 ; G 603
620
+ U 666 ; WX 731 ; N uni029a ; G 604
621
+ U 667 ; WX 685 ; N uni029b ; G 605
622
+ U 668 ; WX 691 ; N uni029c ; G 606
623
+ U 669 ; WX 343 ; N uni029d ; G 607
624
+ U 670 ; WX 732 ; N uni029e ; G 608
625
+ U 671 ; WX 539 ; N uni029f ; G 609
626
+ U 672 ; WX 792 ; N uni02a0 ; G 610
627
+ U 673 ; WX 573 ; N uni02a1 ; G 611
628
+ U 674 ; WX 573 ; N uni02a2 ; G 612
629
+ U 675 ; WX 1156 ; N uni02a3 ; G 613
630
+ U 676 ; WX 1214 ; N uni02a4 ; G 614
631
+ U 677 ; WX 1155 ; N uni02a5 ; G 615
632
+ U 678 ; WX 974 ; N uni02a6 ; G 616
633
+ U 679 ; WX 769 ; N uni02a7 ; G 617
634
+ U 680 ; WX 929 ; N uni02a8 ; G 618
635
+ U 681 ; WX 1026 ; N uni02a9 ; G 619
636
+ U 682 ; WX 792 ; N uni02aa ; G 620
637
+ U 683 ; WX 780 ; N uni02ab ; G 621
638
+ U 684 ; WX 591 ; N uni02ac ; G 622
639
+ U 685 ; WX 415 ; N uni02ad ; G 623
640
+ U 686 ; WX 677 ; N uni02ae ; G 624
641
+ U 687 ; WX 789 ; N uni02af ; G 625
642
+ U 688 ; WX 456 ; N uni02b0 ; G 626
643
+ U 689 ; WX 456 ; N uni02b1 ; G 627
644
+ U 690 ; WX 219 ; N uni02b2 ; G 628
645
+ U 691 ; WX 315 ; N uni02b3 ; G 629
646
+ U 692 ; WX 315 ; N uni02b4 ; G 630
647
+ U 693 ; WX 315 ; N uni02b5 ; G 631
648
+ U 694 ; WX 411 ; N uni02b6 ; G 632
649
+ U 695 ; WX 591 ; N uni02b7 ; G 633
650
+ U 696 ; WX 417 ; N uni02b8 ; G 634
651
+ U 697 ; WX 302 ; N uni02b9 ; G 635
652
+ U 698 ; WX 521 ; N uni02ba ; G 636
653
+ U 699 ; WX 380 ; N uni02bb ; G 637
654
+ U 700 ; WX 380 ; N uni02bc ; G 638
655
+ U 701 ; WX 380 ; N uni02bd ; G 639
656
+ U 702 ; WX 366 ; N uni02be ; G 640
657
+ U 703 ; WX 366 ; N uni02bf ; G 641
658
+ U 704 ; WX 326 ; N uni02c0 ; G 642
659
+ U 705 ; WX 326 ; N uni02c1 ; G 643
660
+ U 706 ; WX 500 ; N uni02c2 ; G 644
661
+ U 707 ; WX 500 ; N uni02c3 ; G 645
662
+ U 708 ; WX 500 ; N uni02c4 ; G 646
663
+ U 709 ; WX 500 ; N uni02c5 ; G 647
664
+ U 710 ; WX 500 ; N uni02c6 ; G 648
665
+ U 711 ; WX 500 ; N uni02c7 ; G 649
666
+ U 712 ; WX 306 ; N uni02c8 ; G 650
667
+ U 713 ; WX 500 ; N uni02c9 ; G 651
668
+ U 714 ; WX 500 ; N uni02ca ; G 652
669
+ U 715 ; WX 500 ; N uni02cb ; G 653
670
+ U 716 ; WX 306 ; N uni02cc ; G 654
671
+ U 717 ; WX 500 ; N uni02cd ; G 655
672
+ U 718 ; WX 500 ; N uni02ce ; G 656
673
+ U 719 ; WX 500 ; N uni02cf ; G 657
674
+ U 720 ; WX 337 ; N uni02d0 ; G 658
675
+ U 721 ; WX 337 ; N uni02d1 ; G 659
676
+ U 722 ; WX 366 ; N uni02d2 ; G 660
677
+ U 723 ; WX 366 ; N uni02d3 ; G 661
678
+ U 724 ; WX 500 ; N uni02d4 ; G 662
679
+ U 725 ; WX 500 ; N uni02d5 ; G 663
680
+ U 726 ; WX 416 ; N uni02d6 ; G 664
681
+ U 727 ; WX 328 ; N uni02d7 ; G 665
682
+ U 728 ; WX 500 ; N uni02d8 ; G 666
683
+ U 729 ; WX 500 ; N uni02d9 ; G 667
684
+ U 730 ; WX 500 ; N uni02da ; G 668
685
+ U 731 ; WX 500 ; N uni02db ; G 669
686
+ U 732 ; WX 500 ; N uni02dc ; G 670
687
+ U 733 ; WX 500 ; N uni02dd ; G 671
688
+ U 734 ; WX 351 ; N uni02de ; G 672
689
+ U 735 ; WX 500 ; N uni02df ; G 673
690
+ U 736 ; WX 412 ; N uni02e0 ; G 674
691
+ U 737 ; WX 219 ; N uni02e1 ; G 675
692
+ U 738 ; WX 381 ; N uni02e2 ; G 676
693
+ U 739 ; WX 413 ; N uni02e3 ; G 677
694
+ U 740 ; WX 326 ; N uni02e4 ; G 678
695
+ U 741 ; WX 500 ; N uni02e5 ; G 679
696
+ U 742 ; WX 500 ; N uni02e6 ; G 680
697
+ U 743 ; WX 500 ; N uni02e7 ; G 681
698
+ U 744 ; WX 500 ; N uni02e8 ; G 682
699
+ U 745 ; WX 500 ; N uni02e9 ; G 683
700
+ U 748 ; WX 500 ; N uni02ec ; G 684
701
+ U 749 ; WX 500 ; N uni02ed ; G 685
702
+ U 750 ; WX 657 ; N uni02ee ; G 686
703
+ U 755 ; WX 500 ; N uni02f3 ; G 687
704
+ U 759 ; WX 500 ; N uni02f7 ; G 688
705
+ U 880 ; WX 698 ; N uni0370 ; G 782
706
+ U 881 ; WX 565 ; N uni0371 ; G 783
707
+ U 882 ; WX 1022 ; N uni0372 ; G 784
708
+ U 883 ; WX 836 ; N uni0373 ; G 785
709
+ U 884 ; WX 302 ; N uni0374 ; G 786
710
+ U 885 ; WX 302 ; N uni0375 ; G 787
711
+ U 886 ; WX 837 ; N uni0376 ; G 788
712
+ U 887 ; WX 701 ; N uni0377 ; G 789
713
+ U 890 ; WX 500 ; N uni037a ; G 790
714
+ U 891 ; WX 593 ; N uni037b ; G 791
715
+ U 892 ; WX 550 ; N uni037c ; G 792
716
+ U 893 ; WX 549 ; N uni037d ; G 793
717
+ U 894 ; WX 400 ; N uni037e ; G 794
718
+ U 900 ; WX 441 ; N uni0384 ; G 795
719
+ U 901 ; WX 500 ; N uni0385 ; G 796
720
+ U 902 ; WX 797 ; N uni0386 ; G 797
721
+ U 903 ; WX 380 ; N uni0387 ; G 798
722
+ U 904 ; WX 846 ; N uni0388 ; G 799
723
+ U 905 ; WX 1009 ; N uni0389 ; G 800
724
+ U 906 ; WX 563 ; N uni038a ; G 801
725
+ U 908 ; WX 891 ; N uni038c ; G 802
726
+ U 910 ; WX 980 ; N uni038e ; G 803
727
+ U 911 ; WX 894 ; N uni038f ; G 804
728
+ U 912 ; WX 390 ; N uni0390 ; G 805
729
+ U 913 ; WX 774 ; N uni0391 ; G 806
730
+ U 914 ; WX 762 ; N uni0392 ; G 807
731
+ U 915 ; WX 637 ; N uni0393 ; G 808
732
+ U 916 ; WX 774 ; N uni0394 ; G 809
733
+ U 917 ; WX 683 ; N uni0395 ; G 810
734
+ U 918 ; WX 725 ; N uni0396 ; G 811
735
+ U 919 ; WX 837 ; N uni0397 ; G 812
736
+ U 920 ; WX 850 ; N uni0398 ; G 813
737
+ U 921 ; WX 372 ; N uni0399 ; G 814
738
+ U 922 ; WX 775 ; N uni039a ; G 815
739
+ U 923 ; WX 774 ; N uni039b ; G 816
740
+ U 924 ; WX 995 ; N uni039c ; G 817
741
+ U 925 ; WX 837 ; N uni039d ; G 818
742
+ U 926 ; WX 632 ; N uni039e ; G 819
743
+ U 927 ; WX 850 ; N uni039f ; G 820
744
+ U 928 ; WX 837 ; N uni03a0 ; G 821
745
+ U 929 ; WX 733 ; N uni03a1 ; G 822
746
+ U 931 ; WX 683 ; N uni03a3 ; G 823
747
+ U 932 ; WX 682 ; N uni03a4 ; G 824
748
+ U 933 ; WX 724 ; N uni03a5 ; G 825
749
+ U 934 ; WX 850 ; N uni03a6 ; G 826
750
+ U 935 ; WX 771 ; N uni03a7 ; G 827
751
+ U 936 ; WX 850 ; N uni03a8 ; G 828
752
+ U 937 ; WX 850 ; N uni03a9 ; G 829
753
+ U 938 ; WX 372 ; N uni03aa ; G 830
754
+ U 939 ; WX 724 ; N uni03ab ; G 831
755
+ U 940 ; WX 687 ; N uni03ac ; G 832
756
+ U 941 ; WX 557 ; N uni03ad ; G 833
757
+ U 942 ; WX 712 ; N uni03ae ; G 834
758
+ U 943 ; WX 390 ; N uni03af ; G 835
759
+ U 944 ; WX 675 ; N uni03b0 ; G 836
760
+ U 945 ; WX 687 ; N uni03b1 ; G 837
761
+ U 946 ; WX 716 ; N uni03b2 ; G 838
762
+ U 947 ; WX 681 ; N uni03b3 ; G 839
763
+ U 948 ; WX 687 ; N uni03b4 ; G 840
764
+ U 949 ; WX 557 ; N uni03b5 ; G 841
765
+ U 950 ; WX 591 ; N uni03b6 ; G 842
766
+ U 951 ; WX 712 ; N uni03b7 ; G 843
767
+ U 952 ; WX 687 ; N uni03b8 ; G 844
768
+ U 953 ; WX 390 ; N uni03b9 ; G 845
769
+ U 954 ; WX 710 ; N uni03ba ; G 846
770
+ U 955 ; WX 633 ; N uni03bb ; G 847
771
+ U 956 ; WX 736 ; N uni03bc ; G 848
772
+ U 957 ; WX 681 ; N uni03bd ; G 849
773
+ U 958 ; WX 591 ; N uni03be ; G 850
774
+ U 959 ; WX 687 ; N uni03bf ; G 851
775
+ U 960 ; WX 791 ; N uni03c0 ; G 852
776
+ U 961 ; WX 716 ; N uni03c1 ; G 853
777
+ U 962 ; WX 593 ; N uni03c2 ; G 854
778
+ U 963 ; WX 779 ; N uni03c3 ; G 855
779
+ U 964 ; WX 638 ; N uni03c4 ; G 856
780
+ U 965 ; WX 675 ; N uni03c5 ; G 857
781
+ U 966 ; WX 782 ; N uni03c6 ; G 858
782
+ U 967 ; WX 645 ; N uni03c7 ; G 859
783
+ U 968 ; WX 794 ; N uni03c8 ; G 860
784
+ U 969 ; WX 869 ; N uni03c9 ; G 861
785
+ U 970 ; WX 390 ; N uni03ca ; G 862
786
+ U 971 ; WX 675 ; N uni03cb ; G 863
787
+ U 972 ; WX 687 ; N uni03cc ; G 864
788
+ U 973 ; WX 675 ; N uni03cd ; G 865
789
+ U 974 ; WX 869 ; N uni03ce ; G 866
790
+ U 975 ; WX 775 ; N uni03cf ; G 867
791
+ U 976 ; WX 651 ; N uni03d0 ; G 868
792
+ U 977 ; WX 661 ; N uni03d1 ; G 869
793
+ U 978 ; WX 746 ; N uni03d2 ; G 870
794
+ U 979 ; WX 981 ; N uni03d3 ; G 871
795
+ U 980 ; WX 746 ; N uni03d4 ; G 872
796
+ U 981 ; WX 796 ; N uni03d5 ; G 873
797
+ U 982 ; WX 869 ; N uni03d6 ; G 874
798
+ U 983 ; WX 744 ; N uni03d7 ; G 875
799
+ U 984 ; WX 850 ; N uni03d8 ; G 876
800
+ U 985 ; WX 687 ; N uni03d9 ; G 877
801
+ U 986 ; WX 734 ; N uni03da ; G 878
802
+ U 987 ; WX 593 ; N uni03db ; G 879
803
+ U 988 ; WX 683 ; N uni03dc ; G 880
804
+ U 989 ; WX 494 ; N uni03dd ; G 881
805
+ U 990 ; WX 702 ; N uni03de ; G 882
806
+ U 991 ; WX 660 ; N uni03df ; G 883
807
+ U 992 ; WX 919 ; N uni03e0 ; G 884
808
+ U 993 ; WX 627 ; N uni03e1 ; G 885
809
+ U 994 ; WX 1093 ; N uni03e2 ; G 886
810
+ U 995 ; WX 837 ; N uni03e3 ; G 887
811
+ U 996 ; WX 832 ; N uni03e4 ; G 888
812
+ U 997 ; WX 716 ; N uni03e5 ; G 889
813
+ U 998 ; WX 928 ; N uni03e6 ; G 890
814
+ U 999 ; WX 744 ; N uni03e7 ; G 891
815
+ U 1000 ; WX 733 ; N uni03e8 ; G 892
816
+ U 1001 ; WX 650 ; N uni03e9 ; G 893
817
+ U 1002 ; WX 789 ; N uni03ea ; G 894
818
+ U 1003 ; WX 671 ; N uni03eb ; G 895
819
+ U 1004 ; WX 752 ; N uni03ec ; G 896
820
+ U 1005 ; WX 716 ; N uni03ed ; G 897
821
+ U 1006 ; WX 682 ; N uni03ee ; G 898
822
+ U 1007 ; WX 590 ; N uni03ef ; G 899
823
+ U 1008 ; WX 744 ; N uni03f0 ; G 900
824
+ U 1009 ; WX 716 ; N uni03f1 ; G 901
825
+ U 1010 ; WX 593 ; N uni03f2 ; G 902
826
+ U 1011 ; WX 343 ; N uni03f3 ; G 903
827
+ U 1012 ; WX 850 ; N uni03f4 ; G 904
828
+ U 1013 ; WX 645 ; N uni03f5 ; G 905
829
+ U 1014 ; WX 644 ; N uni03f6 ; G 906
830
+ U 1015 ; WX 738 ; N uni03f7 ; G 907
831
+ U 1016 ; WX 716 ; N uni03f8 ; G 908
832
+ U 1017 ; WX 734 ; N uni03f9 ; G 909
833
+ U 1018 ; WX 995 ; N uni03fa ; G 910
834
+ U 1019 ; WX 732 ; N uni03fb ; G 911
835
+ U 1020 ; WX 716 ; N uni03fc ; G 912
836
+ U 1021 ; WX 698 ; N uni03fd ; G 913
837
+ U 1022 ; WX 734 ; N uni03fe ; G 914
838
+ U 1023 ; WX 698 ; N uni03ff ; G 915
839
+ U 1024 ; WX 683 ; N uni0400 ; G 916
840
+ U 1025 ; WX 683 ; N uni0401 ; G 917
841
+ U 1026 ; WX 878 ; N uni0402 ; G 918
842
+ U 1027 ; WX 637 ; N uni0403 ; G 919
843
+ U 1028 ; WX 734 ; N uni0404 ; G 920
844
+ U 1029 ; WX 720 ; N uni0405 ; G 921
845
+ U 1030 ; WX 372 ; N uni0406 ; G 922
846
+ U 1031 ; WX 372 ; N uni0407 ; G 923
847
+ U 1032 ; WX 372 ; N uni0408 ; G 924
848
+ U 1033 ; WX 1154 ; N uni0409 ; G 925
849
+ U 1034 ; WX 1130 ; N uni040a ; G 926
850
+ U 1035 ; WX 878 ; N uni040b ; G 927
851
+ U 1036 ; WX 817 ; N uni040c ; G 928
852
+ U 1037 ; WX 837 ; N uni040d ; G 929
853
+ U 1038 ; WX 771 ; N uni040e ; G 930
854
+ U 1039 ; WX 837 ; N uni040f ; G 931
855
+ U 1040 ; WX 774 ; N uni0410 ; G 932
856
+ U 1041 ; WX 762 ; N uni0411 ; G 933
857
+ U 1042 ; WX 762 ; N uni0412 ; G 934
858
+ U 1043 ; WX 637 ; N uni0413 ; G 935
859
+ U 1044 ; WX 891 ; N uni0414 ; G 936
860
+ U 1045 ; WX 683 ; N uni0415 ; G 937
861
+ U 1046 ; WX 1224 ; N uni0416 ; G 938
862
+ U 1047 ; WX 710 ; N uni0417 ; G 939
863
+ U 1048 ; WX 837 ; N uni0418 ; G 940
864
+ U 1049 ; WX 837 ; N uni0419 ; G 941
865
+ U 1050 ; WX 817 ; N uni041a ; G 942
866
+ U 1051 ; WX 831 ; N uni041b ; G 943
867
+ U 1052 ; WX 995 ; N uni041c ; G 944
868
+ U 1053 ; WX 837 ; N uni041d ; G 945
869
+ U 1054 ; WX 850 ; N uni041e ; G 946
870
+ U 1055 ; WX 837 ; N uni041f ; G 947
871
+ U 1056 ; WX 733 ; N uni0420 ; G 948
872
+ U 1057 ; WX 734 ; N uni0421 ; G 949
873
+ U 1058 ; WX 682 ; N uni0422 ; G 950
874
+ U 1059 ; WX 771 ; N uni0423 ; G 951
875
+ U 1060 ; WX 992 ; N uni0424 ; G 952
876
+ U 1061 ; WX 771 ; N uni0425 ; G 953
877
+ U 1062 ; WX 928 ; N uni0426 ; G 954
878
+ U 1063 ; WX 808 ; N uni0427 ; G 955
879
+ U 1064 ; WX 1235 ; N uni0428 ; G 956
880
+ U 1065 ; WX 1326 ; N uni0429 ; G 957
881
+ U 1066 ; WX 939 ; N uni042a ; G 958
882
+ U 1067 ; WX 1036 ; N uni042b ; G 959
883
+ U 1068 ; WX 762 ; N uni042c ; G 960
884
+ U 1069 ; WX 734 ; N uni042d ; G 961
885
+ U 1070 ; WX 1174 ; N uni042e ; G 962
886
+ U 1071 ; WX 770 ; N uni042f ; G 963
887
+ U 1072 ; WX 675 ; N uni0430 ; G 964
888
+ U 1073 ; WX 698 ; N uni0431 ; G 965
889
+ U 1074 ; WX 633 ; N uni0432 ; G 966
890
+ U 1075 ; WX 522 ; N uni0433 ; G 967
891
+ U 1076 ; WX 808 ; N uni0434 ; G 968
892
+ U 1077 ; WX 678 ; N uni0435 ; G 969
893
+ U 1078 ; WX 995 ; N uni0436 ; G 970
894
+ U 1079 ; WX 581 ; N uni0437 ; G 971
895
+ U 1080 ; WX 701 ; N uni0438 ; G 972
896
+ U 1081 ; WX 701 ; N uni0439 ; G 973
897
+ U 1082 ; WX 679 ; N uni043a ; G 974
898
+ U 1083 ; WX 732 ; N uni043b ; G 975
899
+ U 1084 ; WX 817 ; N uni043c ; G 976
900
+ U 1085 ; WX 691 ; N uni043d ; G 977
901
+ U 1086 ; WX 687 ; N uni043e ; G 978
902
+ U 1087 ; WX 691 ; N uni043f ; G 979
903
+ U 1088 ; WX 716 ; N uni0440 ; G 980
904
+ U 1089 ; WX 593 ; N uni0441 ; G 981
905
+ U 1090 ; WX 580 ; N uni0442 ; G 982
906
+ U 1091 ; WX 652 ; N uni0443 ; G 983
907
+ U 1092 ; WX 992 ; N uni0444 ; G 984
908
+ U 1093 ; WX 645 ; N uni0445 ; G 985
909
+ U 1094 ; WX 741 ; N uni0446 ; G 986
910
+ U 1095 ; WX 687 ; N uni0447 ; G 987
911
+ U 1096 ; WX 1062 ; N uni0448 ; G 988
912
+ U 1097 ; WX 1105 ; N uni0449 ; G 989
913
+ U 1098 ; WX 751 ; N uni044a ; G 990
914
+ U 1099 ; WX 904 ; N uni044b ; G 991
915
+ U 1100 ; WX 632 ; N uni044c ; G 992
916
+ U 1101 ; WX 593 ; N uni044d ; G 993
917
+ U 1102 ; WX 972 ; N uni044e ; G 994
918
+ U 1103 ; WX 642 ; N uni044f ; G 995
919
+ U 1104 ; WX 678 ; N uni0450 ; G 996
920
+ U 1105 ; WX 678 ; N uni0451 ; G 997
921
+ U 1106 ; WX 714 ; N uni0452 ; G 998
922
+ U 1107 ; WX 522 ; N uni0453 ; G 999
923
+ U 1108 ; WX 593 ; N uni0454 ; G 1000
924
+ U 1109 ; WX 595 ; N uni0455 ; G 1001
925
+ U 1110 ; WX 343 ; N uni0456 ; G 1002
926
+ U 1111 ; WX 343 ; N uni0457 ; G 1003
927
+ U 1112 ; WX 343 ; N uni0458 ; G 1004
928
+ U 1113 ; WX 991 ; N uni0459 ; G 1005
929
+ U 1114 ; WX 956 ; N uni045a ; G 1006
930
+ U 1115 ; WX 734 ; N uni045b ; G 1007
931
+ U 1116 ; WX 679 ; N uni045c ; G 1008
932
+ U 1117 ; WX 701 ; N uni045d ; G 1009
933
+ U 1118 ; WX 652 ; N uni045e ; G 1010
934
+ U 1119 ; WX 691 ; N uni045f ; G 1011
935
+ U 1120 ; WX 1093 ; N uni0460 ; G 1012
936
+ U 1121 ; WX 869 ; N uni0461 ; G 1013
937
+ U 1122 ; WX 840 ; N uni0462 ; G 1014
938
+ U 1123 ; WX 736 ; N uni0463 ; G 1015
939
+ U 1124 ; WX 1012 ; N uni0464 ; G 1016
940
+ U 1125 ; WX 839 ; N uni0465 ; G 1017
941
+ U 1126 ; WX 992 ; N uni0466 ; G 1018
942
+ U 1127 ; WX 832 ; N uni0467 ; G 1019
943
+ U 1128 ; WX 1358 ; N uni0468 ; G 1020
944
+ U 1129 ; WX 1121 ; N uni0469 ; G 1021
945
+ U 1130 ; WX 850 ; N uni046a ; G 1022
946
+ U 1131 ; WX 687 ; N uni046b ; G 1023
947
+ U 1132 ; WX 1236 ; N uni046c ; G 1024
948
+ U 1133 ; WX 1007 ; N uni046d ; G 1025
949
+ U 1134 ; WX 696 ; N uni046e ; G 1026
950
+ U 1135 ; WX 557 ; N uni046f ; G 1027
951
+ U 1136 ; WX 1075 ; N uni0470 ; G 1028
952
+ U 1137 ; WX 1061 ; N uni0471 ; G 1029
953
+ U 1138 ; WX 850 ; N uni0472 ; G 1030
954
+ U 1139 ; WX 687 ; N uni0473 ; G 1031
955
+ U 1140 ; WX 850 ; N uni0474 ; G 1032
956
+ U 1141 ; WX 695 ; N uni0475 ; G 1033
957
+ U 1142 ; WX 850 ; N uni0476 ; G 1034
958
+ U 1143 ; WX 695 ; N uni0477 ; G 1035
959
+ U 1144 ; WX 1148 ; N uni0478 ; G 1036
960
+ U 1145 ; WX 1043 ; N uni0479 ; G 1037
961
+ U 1146 ; WX 1074 ; N uni047a ; G 1038
962
+ U 1147 ; WX 863 ; N uni047b ; G 1039
963
+ U 1148 ; WX 1405 ; N uni047c ; G 1040
964
+ U 1149 ; WX 1173 ; N uni047d ; G 1041
965
+ U 1150 ; WX 1093 ; N uni047e ; G 1042
966
+ U 1151 ; WX 869 ; N uni047f ; G 1043
967
+ U 1152 ; WX 734 ; N uni0480 ; G 1044
968
+ U 1153 ; WX 593 ; N uni0481 ; G 1045
969
+ U 1154 ; WX 652 ; N uni0482 ; G 1046
970
+ U 1160 ; WX 418 ; N uni0488 ; G 1052
971
+ U 1161 ; WX 418 ; N uni0489 ; G 1053
972
+ U 1162 ; WX 957 ; N uni048a ; G 1054
973
+ U 1163 ; WX 807 ; N uni048b ; G 1055
974
+ U 1164 ; WX 762 ; N uni048c ; G 1056
975
+ U 1165 ; WX 611 ; N uni048d ; G 1057
976
+ U 1166 ; WX 733 ; N uni048e ; G 1058
977
+ U 1167 ; WX 716 ; N uni048f ; G 1059
978
+ U 1168 ; WX 637 ; N uni0490 ; G 1060
979
+ U 1169 ; WX 522 ; N uni0491 ; G 1061
980
+ U 1170 ; WX 666 ; N uni0492 ; G 1062
981
+ U 1171 ; WX 543 ; N uni0493 ; G 1063
982
+ U 1172 ; WX 808 ; N uni0494 ; G 1064
983
+ U 1173 ; WX 669 ; N uni0495 ; G 1065
984
+ U 1174 ; WX 1224 ; N uni0496 ; G 1066
985
+ U 1175 ; WX 995 ; N uni0497 ; G 1067
986
+ U 1176 ; WX 710 ; N uni0498 ; G 1068
987
+ U 1177 ; WX 581 ; N uni0499 ; G 1069
988
+ U 1178 ; WX 775 ; N uni049a ; G 1070
989
+ U 1179 ; WX 679 ; N uni049b ; G 1071
990
+ U 1180 ; WX 817 ; N uni049c ; G 1072
991
+ U 1181 ; WX 679 ; N uni049d ; G 1073
992
+ U 1182 ; WX 817 ; N uni049e ; G 1074
993
+ U 1183 ; WX 679 ; N uni049f ; G 1075
994
+ U 1184 ; WX 1015 ; N uni04a0 ; G 1076
995
+ U 1185 ; WX 826 ; N uni04a1 ; G 1077
996
+ U 1186 ; WX 956 ; N uni04a2 ; G 1078
997
+ U 1187 ; WX 808 ; N uni04a3 ; G 1079
998
+ U 1188 ; WX 1103 ; N uni04a4 ; G 1080
999
+ U 1189 ; WX 874 ; N uni04a5 ; G 1081
1000
+ U 1190 ; WX 1273 ; N uni04a6 ; G 1082
1001
+ U 1191 ; WX 1017 ; N uni04a7 ; G 1083
1002
+ U 1192 ; WX 952 ; N uni04a8 ; G 1084
1003
+ U 1193 ; WX 858 ; N uni04a9 ; G 1085
1004
+ U 1194 ; WX 734 ; N uni04aa ; G 1086
1005
+ U 1195 ; WX 593 ; N uni04ab ; G 1087
1006
+ U 1196 ; WX 682 ; N uni04ac ; G 1088
1007
+ U 1197 ; WX 580 ; N uni04ad ; G 1089
1008
+ U 1198 ; WX 724 ; N uni04ae ; G 1090
1009
+ U 1199 ; WX 652 ; N uni04af ; G 1091
1010
+ U 1200 ; WX 724 ; N uni04b0 ; G 1092
1011
+ U 1201 ; WX 652 ; N uni04b1 ; G 1093
1012
+ U 1202 ; WX 771 ; N uni04b2 ; G 1094
1013
+ U 1203 ; WX 645 ; N uni04b3 ; G 1095
1014
+ U 1204 ; WX 1112 ; N uni04b4 ; G 1096
1015
+ U 1205 ; WX 1000 ; N uni04b5 ; G 1097
1016
+ U 1206 ; WX 808 ; N uni04b6 ; G 1098
1017
+ U 1207 ; WX 687 ; N uni04b7 ; G 1099
1018
+ U 1208 ; WX 808 ; N uni04b8 ; G 1100
1019
+ U 1209 ; WX 687 ; N uni04b9 ; G 1101
1020
+ U 1210 ; WX 808 ; N uni04ba ; G 1102
1021
+ U 1211 ; WX 712 ; N uni04bb ; G 1103
1022
+ U 1212 ; WX 1026 ; N uni04bc ; G 1104
1023
+ U 1213 ; WX 810 ; N uni04bd ; G 1105
1024
+ U 1214 ; WX 1026 ; N uni04be ; G 1106
1025
+ U 1215 ; WX 810 ; N uni04bf ; G 1107
1026
+ U 1216 ; WX 372 ; N uni04c0 ; G 1108
1027
+ U 1217 ; WX 1224 ; N uni04c1 ; G 1109
1028
+ U 1218 ; WX 995 ; N uni04c2 ; G 1110
1029
+ U 1219 ; WX 775 ; N uni04c3 ; G 1111
1030
+ U 1220 ; WX 630 ; N uni04c4 ; G 1112
1031
+ U 1221 ; WX 951 ; N uni04c5 ; G 1113
1032
+ U 1222 ; WX 805 ; N uni04c6 ; G 1114
1033
+ U 1223 ; WX 837 ; N uni04c7 ; G 1115
1034
+ U 1224 ; WX 691 ; N uni04c8 ; G 1116
1035
+ U 1225 ; WX 957 ; N uni04c9 ; G 1117
1036
+ U 1226 ; WX 807 ; N uni04ca ; G 1118
1037
+ U 1227 ; WX 808 ; N uni04cb ; G 1119
1038
+ U 1228 ; WX 687 ; N uni04cc ; G 1120
1039
+ U 1229 ; WX 1115 ; N uni04cd ; G 1121
1040
+ U 1230 ; WX 933 ; N uni04ce ; G 1122
1041
+ U 1231 ; WX 343 ; N uni04cf ; G 1123
1042
+ U 1232 ; WX 774 ; N uni04d0 ; G 1124
1043
+ U 1233 ; WX 675 ; N uni04d1 ; G 1125
1044
+ U 1234 ; WX 774 ; N uni04d2 ; G 1126
1045
+ U 1235 ; WX 675 ; N uni04d3 ; G 1127
1046
+ U 1236 ; WX 1085 ; N uni04d4 ; G 1128
1047
+ U 1237 ; WX 1048 ; N uni04d5 ; G 1129
1048
+ U 1238 ; WX 683 ; N uni04d6 ; G 1130
1049
+ U 1239 ; WX 678 ; N uni04d7 ; G 1131
1050
+ U 1240 ; WX 849 ; N uni04d8 ; G 1132
1051
+ U 1241 ; WX 678 ; N uni04d9 ; G 1133
1052
+ U 1242 ; WX 849 ; N uni04da ; G 1134
1053
+ U 1243 ; WX 678 ; N uni04db ; G 1135
1054
+ U 1244 ; WX 1224 ; N uni04dc ; G 1136
1055
+ U 1245 ; WX 995 ; N uni04dd ; G 1137
1056
+ U 1246 ; WX 710 ; N uni04de ; G 1138
1057
+ U 1247 ; WX 581 ; N uni04df ; G 1139
1058
+ U 1248 ; WX 772 ; N uni04e0 ; G 1140
1059
+ U 1249 ; WX 641 ; N uni04e1 ; G 1141
1060
+ U 1250 ; WX 837 ; N uni04e2 ; G 1142
1061
+ U 1251 ; WX 701 ; N uni04e3 ; G 1143
1062
+ U 1252 ; WX 837 ; N uni04e4 ; G 1144
1063
+ U 1253 ; WX 701 ; N uni04e5 ; G 1145
1064
+ U 1254 ; WX 850 ; N uni04e6 ; G 1146
1065
+ U 1255 ; WX 687 ; N uni04e7 ; G 1147
1066
+ U 1256 ; WX 850 ; N uni04e8 ; G 1148
1067
+ U 1257 ; WX 687 ; N uni04e9 ; G 1149
1068
+ U 1258 ; WX 850 ; N uni04ea ; G 1150
1069
+ U 1259 ; WX 687 ; N uni04eb ; G 1151
1070
+ U 1260 ; WX 734 ; N uni04ec ; G 1152
1071
+ U 1261 ; WX 593 ; N uni04ed ; G 1153
1072
+ U 1262 ; WX 771 ; N uni04ee ; G 1154
1073
+ U 1263 ; WX 652 ; N uni04ef ; G 1155
1074
+ U 1264 ; WX 771 ; N uni04f0 ; G 1156
1075
+ U 1265 ; WX 652 ; N uni04f1 ; G 1157
1076
+ U 1266 ; WX 771 ; N uni04f2 ; G 1158
1077
+ U 1267 ; WX 652 ; N uni04f3 ; G 1159
1078
+ U 1268 ; WX 808 ; N uni04f4 ; G 1160
1079
+ U 1269 ; WX 687 ; N uni04f5 ; G 1161
1080
+ U 1270 ; WX 637 ; N uni04f6 ; G 1162
1081
+ U 1271 ; WX 522 ; N uni04f7 ; G 1163
1082
+ U 1272 ; WX 1036 ; N uni04f8 ; G 1164
1083
+ U 1273 ; WX 904 ; N uni04f9 ; G 1165
1084
+ U 1274 ; WX 666 ; N uni04fa ; G 1166
1085
+ U 1275 ; WX 543 ; N uni04fb ; G 1167
1086
+ U 1276 ; WX 771 ; N uni04fc ; G 1168
1087
+ U 1277 ; WX 645 ; N uni04fd ; G 1169
1088
+ U 1278 ; WX 771 ; N uni04fe ; G 1170
1089
+ U 1279 ; WX 645 ; N uni04ff ; G 1171
1090
+ U 1280 ; WX 762 ; N uni0500 ; G 1172
1091
+ U 1281 ; WX 608 ; N uni0501 ; G 1173
1092
+ U 1282 ; WX 1159 ; N uni0502 ; G 1174
1093
+ U 1283 ; WX 893 ; N uni0503 ; G 1175
1094
+ U 1284 ; WX 1119 ; N uni0504 ; G 1176
1095
+ U 1285 ; WX 920 ; N uni0505 ; G 1177
1096
+ U 1286 ; WX 828 ; N uni0506 ; G 1178
1097
+ U 1287 ; WX 693 ; N uni0507 ; G 1179
1098
+ U 1288 ; WX 1242 ; N uni0508 ; G 1180
1099
+ U 1289 ; WX 1017 ; N uni0509 ; G 1181
1100
+ U 1290 ; WX 1289 ; N uni050a ; G 1182
1101
+ U 1291 ; WX 1013 ; N uni050b ; G 1183
1102
+ U 1292 ; WX 839 ; N uni050c ; G 1184
1103
+ U 1293 ; WX 638 ; N uni050d ; G 1185
1104
+ U 1294 ; WX 938 ; N uni050e ; G 1186
1105
+ U 1295 ; WX 803 ; N uni050f ; G 1187
1106
+ U 1296 ; WX 696 ; N uni0510 ; G 1188
1107
+ U 1297 ; WX 557 ; N uni0511 ; G 1189
1108
+ U 1298 ; WX 831 ; N uni0512 ; G 1190
1109
+ U 1299 ; WX 732 ; N uni0513 ; G 1191
1110
+ U 1300 ; WX 1286 ; N uni0514 ; G 1192
1111
+ U 1301 ; WX 1068 ; N uni0515 ; G 1193
1112
+ U 1302 ; WX 1065 ; N uni0516 ; G 1194
1113
+ U 1303 ; WX 979 ; N uni0517 ; G 1195
1114
+ U 1304 ; WX 1082 ; N uni0518 ; G 1196
1115
+ U 1305 ; WX 1013 ; N uni0519 ; G 1197
1116
+ U 1306 ; WX 850 ; N uni051a ; G 1198
1117
+ U 1307 ; WX 716 ; N uni051b ; G 1199
1118
+ U 1308 ; WX 1103 ; N uni051c ; G 1200
1119
+ U 1309 ; WX 924 ; N uni051d ; G 1201
1120
+ U 1312 ; WX 1267 ; N uni0520 ; G 1202
1121
+ U 1313 ; WX 1059 ; N uni0521 ; G 1203
1122
+ U 1314 ; WX 1273 ; N uni0522 ; G 1204
1123
+ U 1315 ; WX 1017 ; N uni0523 ; G 1205
1124
+ U 1316 ; WX 957 ; N uni0524 ; G 1206
1125
+ U 1317 ; WX 807 ; N uni0525 ; G 1207
1126
+ U 1329 ; WX 984 ; N uni0531 ; G 1208
1127
+ U 1330 ; WX 812 ; N uni0532 ; G 1209
1128
+ U 1331 ; WX 984 ; N uni0533 ; G 1210
1129
+ U 1332 ; WX 984 ; N uni0534 ; G 1211
1130
+ U 1333 ; WX 812 ; N uni0535 ; G 1212
1131
+ U 1334 ; WX 777 ; N uni0536 ; G 1213
1132
+ U 1335 ; WX 812 ; N uni0537 ; G 1214
1133
+ U 1336 ; WX 812 ; N uni0538 ; G 1215
1134
+ U 1337 ; WX 975 ; N uni0539 ; G 1216
1135
+ U 1338 ; WX 984 ; N uni053a ; G 1217
1136
+ U 1339 ; WX 812 ; N uni053b ; G 1218
1137
+ U 1340 ; WX 710 ; N uni053c ; G 1219
1138
+ U 1341 ; WX 1078 ; N uni053d ; G 1220
1139
+ U 1342 ; WX 1136 ; N uni053e ; G 1221
1140
+ U 1343 ; WX 812 ; N uni053f ; G 1222
1141
+ U 1344 ; WX 710 ; N uni0540 ; G 1223
1142
+ U 1345 ; WX 757 ; N uni0541 ; G 1224
1143
+ U 1346 ; WX 984 ; N uni0542 ; G 1225
1144
+ U 1347 ; WX 876 ; N uni0543 ; G 1226
1145
+ U 1348 ; WX 984 ; N uni0544 ; G 1227
1146
+ U 1349 ; WX 793 ; N uni0545 ; G 1228
1147
+ U 1350 ; WX 984 ; N uni0546 ; G 1229
1148
+ U 1351 ; WX 812 ; N uni0547 ; G 1230
1149
+ U 1352 ; WX 812 ; N uni0548 ; G 1231
1150
+ U 1353 ; WX 812 ; N uni0549 ; G 1232
1151
+ U 1354 ; WX 958 ; N uni054a ; G 1233
1152
+ U 1355 ; WX 777 ; N uni054b ; G 1234
1153
+ U 1356 ; WX 984 ; N uni054c ; G 1235
1154
+ U 1357 ; WX 812 ; N uni054d ; G 1236
1155
+ U 1358 ; WX 984 ; N uni054e ; G 1237
1156
+ U 1359 ; WX 720 ; N uni054f ; G 1238
1157
+ U 1360 ; WX 812 ; N uni0550 ; G 1239
1158
+ U 1361 ; WX 793 ; N uni0551 ; G 1240
1159
+ U 1362 ; WX 895 ; N uni0552 ; G 1241
1160
+ U 1363 ; WX 850 ; N uni0553 ; G 1242
1161
+ U 1364 ; WX 936 ; N uni0554 ; G 1243
1162
+ U 1365 ; WX 850 ; N uni0555 ; G 1244
1163
+ U 1366 ; WX 720 ; N uni0556 ; G 1245
1164
+ U 1369 ; WX 366 ; N uni0559 ; G 1246
1165
+ U 1370 ; WX 380 ; N uni055a ; G 1247
1166
+ U 1371 ; WX 550 ; N uni055b ; G 1248
1167
+ U 1372 ; WX 550 ; N uni055c ; G 1249
1168
+ U 1373 ; WX 380 ; N uni055d ; G 1250
1169
+ U 1374 ; WX 546 ; N uni055e ; G 1251
1170
+ U 1375 ; WX 521 ; N uni055f ; G 1252
1171
+ U 1377 ; WX 1042 ; N uni0561 ; G 1253
1172
+ U 1378 ; WX 712 ; N uni0562 ; G 1254
1173
+ U 1379 ; WX 866 ; N uni0563 ; G 1255
1174
+ U 1380 ; WX 868 ; N uni0564 ; G 1256
1175
+ U 1381 ; WX 712 ; N uni0565 ; G 1257
1176
+ U 1382 ; WX 817 ; N uni0566 ; G 1258
1177
+ U 1383 ; WX 653 ; N uni0567 ; G 1259
1178
+ U 1384 ; WX 712 ; N uni0568 ; G 1260
1179
+ U 1385 ; WX 811 ; N uni0569 ; G 1261
1180
+ U 1386 ; WX 817 ; N uni056a ; G 1262
1181
+ U 1387 ; WX 712 ; N uni056b ; G 1263
1182
+ U 1388 ; WX 498 ; N uni056c ; G 1264
1183
+ U 1389 ; WX 1018 ; N uni056d ; G 1265
1184
+ U 1390 ; WX 716 ; N uni056e ; G 1266
1185
+ U 1391 ; WX 712 ; N uni056f ; G 1267
1186
+ U 1392 ; WX 712 ; N uni0570 ; G 1268
1187
+ U 1393 ; WX 716 ; N uni0571 ; G 1269
1188
+ U 1394 ; WX 819 ; N uni0572 ; G 1270
1189
+ U 1395 ; WX 712 ; N uni0573 ; G 1271
1190
+ U 1396 ; WX 751 ; N uni0574 ; G 1272
1191
+ U 1397 ; WX 343 ; N uni0575 ; G 1273
1192
+ U 1398 ; WX 882 ; N uni0576 ; G 1274
1193
+ U 1399 ; WX 559 ; N uni0577 ; G 1275
1194
+ U 1400 ; WX 712 ; N uni0578 ; G 1276
1195
+ U 1401 ; WX 559 ; N uni0579 ; G 1277
1196
+ U 1402 ; WX 1042 ; N uni057a ; G 1278
1197
+ U 1403 ; WX 559 ; N uni057b ; G 1279
1198
+ U 1404 ; WX 863 ; N uni057c ; G 1280
1199
+ U 1405 ; WX 712 ; N uni057d ; G 1281
1200
+ U 1406 ; WX 813 ; N uni057e ; G 1282
1201
+ U 1407 ; WX 1042 ; N uni057f ; G 1283
1202
+ U 1408 ; WX 712 ; N uni0580 ; G 1284
1203
+ U 1409 ; WX 716 ; N uni0581 ; G 1285
1204
+ U 1410 ; WX 571 ; N uni0582 ; G 1286
1205
+ U 1411 ; WX 1042 ; N uni0583 ; G 1287
1206
+ U 1412 ; WX 778 ; N uni0584 ; G 1288
1207
+ U 1413 ; WX 687 ; N uni0585 ; G 1289
1208
+ U 1414 ; WX 720 ; N uni0586 ; G 1290
1209
+ U 1415 ; WX 862 ; N uni0587 ; G 1291
1210
+ U 1417 ; WX 400 ; N uni0589 ; G 1292
1211
+ U 1418 ; WX 487 ; N uni058a ; G 1293
1212
+ U 1470 ; WX 415 ; N uni05be ; G 1308
1213
+ U 1472 ; WX 372 ; N uni05c0 ; G 1310
1214
+ U 1475 ; WX 372 ; N uni05c3 ; G 1313
1215
+ U 1478 ; WX 497 ; N uni05c6 ; G 1314
1216
+ U 1488 ; WX 751 ; N uni05d0 ; G 1316
1217
+ U 1489 ; WX 673 ; N uni05d1 ; G 1317
1218
+ U 1490 ; WX 537 ; N uni05d2 ; G 1318
1219
+ U 1491 ; WX 654 ; N uni05d3 ; G 1319
1220
+ U 1492 ; WX 712 ; N uni05d4 ; G 1320
1221
+ U 1493 ; WX 343 ; N uni05d5 ; G 1321
1222
+ U 1494 ; WX 491 ; N uni05d6 ; G 1322
1223
+ U 1495 ; WX 712 ; N uni05d7 ; G 1323
1224
+ U 1496 ; WX 724 ; N uni05d8 ; G 1324
1225
+ U 1497 ; WX 343 ; N uni05d9 ; G 1325
1226
+ U 1498 ; WX 649 ; N uni05da ; G 1326
1227
+ U 1499 ; WX 650 ; N uni05db ; G 1327
1228
+ U 1500 ; WX 679 ; N uni05dc ; G 1328
1229
+ U 1501 ; WX 712 ; N uni05dd ; G 1329
1230
+ U 1502 ; WX 775 ; N uni05de ; G 1330
1231
+ U 1503 ; WX 343 ; N uni05df ; G 1331
1232
+ U 1504 ; WX 497 ; N uni05e0 ; G 1332
1233
+ U 1505 ; WX 773 ; N uni05e1 ; G 1333
1234
+ U 1506 ; WX 678 ; N uni05e2 ; G 1334
1235
+ U 1507 ; WX 718 ; N uni05e3 ; G 1335
1236
+ U 1508 ; WX 687 ; N uni05e4 ; G 1336
1237
+ U 1509 ; WX 628 ; N uni05e5 ; G 1337
1238
+ U 1510 ; WX 751 ; N uni05e6 ; G 1338
1239
+ U 1511 ; WX 729 ; N uni05e7 ; G 1339
1240
+ U 1512 ; WX 649 ; N uni05e8 ; G 1340
1241
+ U 1513 ; WX 949 ; N uni05e9 ; G 1341
1242
+ U 1514 ; WX 751 ; N uni05ea ; G 1342
1243
+ U 1520 ; WX 664 ; N uni05f0 ; G 1343
1244
+ U 1521 ; WX 664 ; N uni05f1 ; G 1344
1245
+ U 1522 ; WX 663 ; N uni05f2 ; G 1345
1246
+ U 1523 ; WX 444 ; N uni05f3 ; G 1346
1247
+ U 1524 ; WX 710 ; N uni05f4 ; G 1347
1248
+ U 1542 ; WX 667 ; N uni0606 ; G 1348
1249
+ U 1543 ; WX 667 ; N uni0607 ; G 1349
1250
+ U 1545 ; WX 884 ; N uni0609 ; G 1350
1251
+ U 1546 ; WX 1157 ; N uni060a ; G 1351
1252
+ U 1548 ; WX 380 ; N uni060c ; G 1352
1253
+ U 1563 ; WX 400 ; N uni061b ; G 1354
1254
+ U 1567 ; WX 580 ; N uni061f ; G 1355
1255
+ U 1569 ; WX 511 ; N uni0621 ; G 1356
1256
+ U 1570 ; WX 343 ; N uni0622 ; G 1357
1257
+ U 1571 ; WX 343 ; N uni0623 ; G 1358
1258
+ U 1572 ; WX 622 ; N uni0624 ; G 1359
1259
+ U 1573 ; WX 343 ; N uni0625 ; G 1360
1260
+ U 1574 ; WX 917 ; N uni0626 ; G 1361
1261
+ U 1575 ; WX 343 ; N uni0627 ; G 1362
1262
+ U 1576 ; WX 1005 ; N uni0628 ; G 1363
1263
+ U 1577 ; WX 590 ; N uni0629 ; G 1364
1264
+ U 1578 ; WX 1005 ; N uni062a ; G 1365
1265
+ U 1579 ; WX 1005 ; N uni062b ; G 1366
1266
+ U 1580 ; WX 721 ; N uni062c ; G 1367
1267
+ U 1581 ; WX 721 ; N uni062d ; G 1368
1268
+ U 1582 ; WX 721 ; N uni062e ; G 1369
1269
+ U 1583 ; WX 513 ; N uni062f ; G 1370
1270
+ U 1584 ; WX 513 ; N uni0630 ; G 1371
1271
+ U 1585 ; WX 576 ; N uni0631 ; G 1372
1272
+ U 1586 ; WX 576 ; N uni0632 ; G 1373
1273
+ U 1587 ; WX 1380 ; N uni0633 ; G 1374
1274
+ U 1588 ; WX 1380 ; N uni0634 ; G 1375
1275
+ U 1589 ; WX 1345 ; N uni0635 ; G 1376
1276
+ U 1590 ; WX 1345 ; N uni0636 ; G 1377
1277
+ U 1591 ; WX 1039 ; N uni0637 ; G 1378
1278
+ U 1592 ; WX 1039 ; N uni0638 ; G 1379
1279
+ U 1593 ; WX 683 ; N uni0639 ; G 1380
1280
+ U 1594 ; WX 683 ; N uni063a ; G 1381
1281
+ U 1600 ; WX 342 ; N uni0640 ; G 1382
1282
+ U 1601 ; WX 1162 ; N uni0641 ; G 1383
1283
+ U 1602 ; WX 894 ; N uni0642 ; G 1384
1284
+ U 1603 ; WX 917 ; N uni0643 ; G 1385
1285
+ U 1604 ; WX 868 ; N uni0644 ; G 1386
1286
+ U 1605 ; WX 733 ; N uni0645 ; G 1387
1287
+ U 1606 ; WX 854 ; N uni0646 ; G 1388
1288
+ U 1607 ; WX 590 ; N uni0647 ; G 1389
1289
+ U 1608 ; WX 622 ; N uni0648 ; G 1390
1290
+ U 1609 ; WX 917 ; N uni0649 ; G 1391
1291
+ U 1610 ; WX 917 ; N uni064a ; G 1392
1292
+ U 1626 ; WX 500 ; N uni065a ; G 1405
1293
+ U 1632 ; WX 610 ; N uni0660 ; G 1406
1294
+ U 1633 ; WX 610 ; N uni0661 ; G 1407
1295
+ U 1634 ; WX 610 ; N uni0662 ; G 1408
1296
+ U 1635 ; WX 610 ; N uni0663 ; G 1409
1297
+ U 1636 ; WX 610 ; N uni0664 ; G 1410
1298
+ U 1637 ; WX 610 ; N uni0665 ; G 1411
1299
+ U 1638 ; WX 610 ; N uni0666 ; G 1412
1300
+ U 1639 ; WX 610 ; N uni0667 ; G 1413
1301
+ U 1640 ; WX 610 ; N uni0668 ; G 1414
1302
+ U 1641 ; WX 610 ; N uni0669 ; G 1415
1303
+ U 1642 ; WX 610 ; N uni066a ; G 1416
1304
+ U 1643 ; WX 374 ; N uni066b ; G 1417
1305
+ U 1644 ; WX 380 ; N uni066c ; G 1418
1306
+ U 1645 ; WX 545 ; N uni066d ; G 1419
1307
+ U 1646 ; WX 1005 ; N uni066e ; G 1420
1308
+ U 1647 ; WX 894 ; N uni066f ; G 1421
1309
+ U 1652 ; WX 292 ; N uni0674 ; G 1423
1310
+ U 1657 ; WX 1005 ; N uni0679 ; G 1424
1311
+ U 1658 ; WX 1005 ; N uni067a ; G 1425
1312
+ U 1659 ; WX 1005 ; N uni067b ; G 1426
1313
+ U 1660 ; WX 1005 ; N uni067c ; G 1427
1314
+ U 1661 ; WX 1005 ; N uni067d ; G 1428
1315
+ U 1662 ; WX 1005 ; N uni067e ; G 1429
1316
+ U 1663 ; WX 1005 ; N uni067f ; G 1430
1317
+ U 1664 ; WX 1005 ; N uni0680 ; G 1431
1318
+ U 1665 ; WX 721 ; N uni0681 ; G 1432
1319
+ U 1666 ; WX 721 ; N uni0682 ; G 1433
1320
+ U 1667 ; WX 721 ; N uni0683 ; G 1434
1321
+ U 1668 ; WX 721 ; N uni0684 ; G 1435
1322
+ U 1669 ; WX 721 ; N uni0685 ; G 1436
1323
+ U 1670 ; WX 721 ; N uni0686 ; G 1437
1324
+ U 1671 ; WX 721 ; N uni0687 ; G 1438
1325
+ U 1672 ; WX 445 ; N uni0688 ; G 1439
1326
+ U 1673 ; WX 445 ; N uni0689 ; G 1440
1327
+ U 1674 ; WX 445 ; N uni068a ; G 1441
1328
+ U 1675 ; WX 445 ; N uni068b ; G 1442
1329
+ U 1676 ; WX 445 ; N uni068c ; G 1443
1330
+ U 1677 ; WX 445 ; N uni068d ; G 1444
1331
+ U 1678 ; WX 445 ; N uni068e ; G 1445
1332
+ U 1679 ; WX 445 ; N uni068f ; G 1446
1333
+ U 1680 ; WX 445 ; N uni0690 ; G 1447
1334
+ U 1681 ; WX 576 ; N uni0691 ; G 1448
1335
+ U 1682 ; WX 576 ; N uni0692 ; G 1449
1336
+ U 1683 ; WX 576 ; N uni0693 ; G 1450
1337
+ U 1684 ; WX 576 ; N uni0694 ; G 1451
1338
+ U 1685 ; WX 681 ; N uni0695 ; G 1452
1339
+ U 1686 ; WX 576 ; N uni0696 ; G 1453
1340
+ U 1687 ; WX 576 ; N uni0697 ; G 1454
1341
+ U 1688 ; WX 576 ; N uni0698 ; G 1455
1342
+ U 1689 ; WX 576 ; N uni0699 ; G 1456
1343
+ U 1690 ; WX 1380 ; N uni069a ; G 1457
1344
+ U 1691 ; WX 1380 ; N uni069b ; G 1458
1345
+ U 1692 ; WX 1380 ; N uni069c ; G 1459
1346
+ U 1693 ; WX 1345 ; N uni069d ; G 1460
1347
+ U 1694 ; WX 1345 ; N uni069e ; G 1461
1348
+ U 1695 ; WX 1039 ; N uni069f ; G 1462
1349
+ U 1696 ; WX 683 ; N uni06a0 ; G 1463
1350
+ U 1697 ; WX 1162 ; N uni06a1 ; G 1464
1351
+ U 1698 ; WX 1162 ; N uni06a2 ; G 1465
1352
+ U 1699 ; WX 1162 ; N uni06a3 ; G 1466
1353
+ U 1700 ; WX 1162 ; N uni06a4 ; G 1467
1354
+ U 1701 ; WX 1162 ; N uni06a5 ; G 1468
1355
+ U 1702 ; WX 1162 ; N uni06a6 ; G 1469
1356
+ U 1703 ; WX 894 ; N uni06a7 ; G 1470
1357
+ U 1704 ; WX 894 ; N uni06a8 ; G 1471
1358
+ U 1705 ; WX 1024 ; N uni06a9 ; G 1472
1359
+ U 1706 ; WX 1271 ; N uni06aa ; G 1473
1360
+ U 1707 ; WX 1024 ; N uni06ab ; G 1474
1361
+ U 1708 ; WX 917 ; N uni06ac ; G 1475
1362
+ U 1709 ; WX 917 ; N uni06ad ; G 1476
1363
+ U 1710 ; WX 917 ; N uni06ae ; G 1477
1364
+ U 1711 ; WX 1024 ; N uni06af ; G 1478
1365
+ U 1712 ; WX 1024 ; N uni06b0 ; G 1479
1366
+ U 1713 ; WX 1024 ; N uni06b1 ; G 1480
1367
+ U 1714 ; WX 1024 ; N uni06b2 ; G 1481
1368
+ U 1715 ; WX 1024 ; N uni06b3 ; G 1482
1369
+ U 1716 ; WX 1024 ; N uni06b4 ; G 1483
1370
+ U 1717 ; WX 868 ; N uni06b5 ; G 1484
1371
+ U 1718 ; WX 868 ; N uni06b6 ; G 1485
1372
+ U 1719 ; WX 868 ; N uni06b7 ; G 1486
1373
+ U 1720 ; WX 868 ; N uni06b8 ; G 1487
1374
+ U 1721 ; WX 854 ; N uni06b9 ; G 1488
1375
+ U 1722 ; WX 854 ; N uni06ba ; G 1489
1376
+ U 1723 ; WX 854 ; N uni06bb ; G 1490
1377
+ U 1724 ; WX 854 ; N uni06bc ; G 1491
1378
+ U 1725 ; WX 854 ; N uni06bd ; G 1492
1379
+ U 1726 ; WX 938 ; N uni06be ; G 1493
1380
+ U 1727 ; WX 721 ; N uni06bf ; G 1494
1381
+ U 1734 ; WX 622 ; N uni06c6 ; G 1495
1382
+ U 1740 ; WX 917 ; N uni06cc ; G 1496
1383
+ U 1742 ; WX 917 ; N uni06ce ; G 1497
1384
+ U 1749 ; WX 590 ; N uni06d5 ; G 1498
1385
+ U 1776 ; WX 610 ; N uni06f0 ; G 1499
1386
+ U 1777 ; WX 610 ; N uni06f1 ; G 1500
1387
+ U 1778 ; WX 610 ; N uni06f2 ; G 1501
1388
+ U 1779 ; WX 610 ; N uni06f3 ; G 1502
1389
+ U 1780 ; WX 610 ; N uni06f4 ; G 1503
1390
+ U 1781 ; WX 610 ; N uni06f5 ; G 1504
1391
+ U 1782 ; WX 610 ; N uni06f6 ; G 1505
1392
+ U 1783 ; WX 610 ; N uni06f7 ; G 1506
1393
+ U 1784 ; WX 610 ; N uni06f8 ; G 1507
1394
+ U 1785 ; WX 610 ; N uni06f9 ; G 1508
1395
+ U 1984 ; WX 696 ; N uni07c0 ; G 1509
1396
+ U 1985 ; WX 696 ; N uni07c1 ; G 1510
1397
+ U 1986 ; WX 696 ; N uni07c2 ; G 1511
1398
+ U 1987 ; WX 696 ; N uni07c3 ; G 1512
1399
+ U 1988 ; WX 696 ; N uni07c4 ; G 1513
1400
+ U 1989 ; WX 696 ; N uni07c5 ; G 1514
1401
+ U 1990 ; WX 696 ; N uni07c6 ; G 1515
1402
+ U 1991 ; WX 696 ; N uni07c7 ; G 1516
1403
+ U 1992 ; WX 696 ; N uni07c8 ; G 1517
1404
+ U 1993 ; WX 696 ; N uni07c9 ; G 1518
1405
+ U 1994 ; WX 343 ; N uni07ca ; G 1519
1406
+ U 1995 ; WX 547 ; N uni07cb ; G 1520
1407
+ U 1996 ; WX 543 ; N uni07cc ; G 1521
1408
+ U 1997 ; WX 652 ; N uni07cd ; G 1522
1409
+ U 1998 ; WX 691 ; N uni07ce ; G 1523
1410
+ U 1999 ; WX 691 ; N uni07cf ; G 1524
1411
+ U 2000 ; WX 594 ; N uni07d0 ; G 1525
1412
+ U 2001 ; WX 691 ; N uni07d1 ; G 1526
1413
+ U 2002 ; WX 904 ; N uni07d2 ; G 1527
1414
+ U 2003 ; WX 551 ; N uni07d3 ; G 1528
1415
+ U 2004 ; WX 551 ; N uni07d4 ; G 1529
1416
+ U 2005 ; WX 627 ; N uni07d5 ; G 1530
1417
+ U 2006 ; WX 688 ; N uni07d6 ; G 1531
1418
+ U 2007 ; WX 444 ; N uni07d7 ; G 1532
1419
+ U 2008 ; WX 1022 ; N uni07d8 ; G 1533
1420
+ U 2009 ; WX 506 ; N uni07d9 ; G 1534
1421
+ U 2010 ; WX 826 ; N uni07da ; G 1535
1422
+ U 2011 ; WX 691 ; N uni07db ; G 1536
1423
+ U 2012 ; WX 652 ; N uni07dc ; G 1537
1424
+ U 2013 ; WX 912 ; N uni07dd ; G 1538
1425
+ U 2014 ; WX 627 ; N uni07de ; G 1539
1426
+ U 2015 ; WX 707 ; N uni07df ; G 1540
1427
+ U 2016 ; WX 506 ; N uni07e0 ; G 1541
1428
+ U 2017 ; WX 652 ; N uni07e1 ; G 1542
1429
+ U 2018 ; WX 574 ; N uni07e2 ; G 1543
1430
+ U 2019 ; WX 627 ; N uni07e3 ; G 1544
1431
+ U 2020 ; WX 627 ; N uni07e4 ; G 1545
1432
+ U 2021 ; WX 627 ; N uni07e5 ; G 1546
1433
+ U 2022 ; WX 574 ; N uni07e6 ; G 1547
1434
+ U 2023 ; WX 574 ; N uni07e7 ; G 1548
1435
+ U 2036 ; WX 380 ; N uni07f4 ; G 1558
1436
+ U 2037 ; WX 380 ; N uni07f5 ; G 1559
1437
+ U 2040 ; WX 691 ; N uni07f8 ; G 1560
1438
+ U 2041 ; WX 691 ; N uni07f9 ; G 1561
1439
+ U 2042 ; WX 415 ; N uni07fa ; G 1562
1440
+ U 3647 ; WX 696 ; N uni0e3f ; G 1563
1441
+ U 3713 ; WX 790 ; N uni0e81 ; G 1564
1442
+ U 3714 ; WX 748 ; N uni0e82 ; G 1565
1443
+ U 3716 ; WX 749 ; N uni0e84 ; G 1566
1444
+ U 3719 ; WX 569 ; N uni0e87 ; G 1567
1445
+ U 3720 ; WX 742 ; N uni0e88 ; G 1568
1446
+ U 3722 ; WX 744 ; N uni0e8a ; G 1569
1447
+ U 3725 ; WX 761 ; N uni0e8d ; G 1570
1448
+ U 3732 ; WX 706 ; N uni0e94 ; G 1571
1449
+ U 3733 ; WX 704 ; N uni0e95 ; G 1572
1450
+ U 3734 ; WX 747 ; N uni0e96 ; G 1573
1451
+ U 3735 ; WX 819 ; N uni0e97 ; G 1574
1452
+ U 3737 ; WX 730 ; N uni0e99 ; G 1575
1453
+ U 3738 ; WX 727 ; N uni0e9a ; G 1576
1454
+ U 3739 ; WX 727 ; N uni0e9b ; G 1577
1455
+ U 3740 ; WX 922 ; N uni0e9c ; G 1578
1456
+ U 3741 ; WX 827 ; N uni0e9d ; G 1579
1457
+ U 3742 ; WX 866 ; N uni0e9e ; G 1580
1458
+ U 3743 ; WX 866 ; N uni0e9f ; G 1581
1459
+ U 3745 ; WX 836 ; N uni0ea1 ; G 1582
1460
+ U 3746 ; WX 761 ; N uni0ea2 ; G 1583
1461
+ U 3747 ; WX 770 ; N uni0ea3 ; G 1584
1462
+ U 3749 ; WX 769 ; N uni0ea5 ; G 1585
1463
+ U 3751 ; WX 713 ; N uni0ea7 ; G 1586
1464
+ U 3754 ; WX 827 ; N uni0eaa ; G 1587
1465
+ U 3755 ; WX 1031 ; N uni0eab ; G 1588
1466
+ U 3757 ; WX 724 ; N uni0ead ; G 1589
1467
+ U 3758 ; WX 784 ; N uni0eae ; G 1590
1468
+ U 3759 ; WX 934 ; N uni0eaf ; G 1591
1469
+ U 3760 ; WX 688 ; N uni0eb0 ; G 1592
1470
+ U 3762 ; WX 610 ; N uni0eb2 ; G 1594
1471
+ U 3763 ; WX 610 ; N uni0eb3 ; G 1595
1472
+ U 3773 ; WX 670 ; N uni0ebd ; G 1604
1473
+ U 3776 ; WX 516 ; N uni0ec0 ; G 1605
1474
+ U 3777 ; WX 860 ; N uni0ec1 ; G 1606
1475
+ U 3778 ; WX 516 ; N uni0ec2 ; G 1607
1476
+ U 3779 ; WX 650 ; N uni0ec3 ; G 1608
1477
+ U 3780 ; WX 632 ; N uni0ec4 ; G 1609
1478
+ U 3782 ; WX 759 ; N uni0ec6 ; G 1610
1479
+ U 3792 ; WX 771 ; N uni0ed0 ; G 1617
1480
+ U 3793 ; WX 771 ; N uni0ed1 ; G 1618
1481
+ U 3794 ; WX 693 ; N uni0ed2 ; G 1619
1482
+ U 3795 ; WX 836 ; N uni0ed3 ; G 1620
1483
+ U 3796 ; WX 729 ; N uni0ed4 ; G 1621
1484
+ U 3797 ; WX 729 ; N uni0ed5 ; G 1622
1485
+ U 3798 ; WX 849 ; N uni0ed6 ; G 1623
1486
+ U 3799 ; WX 790 ; N uni0ed7 ; G 1624
1487
+ U 3800 ; WX 759 ; N uni0ed8 ; G 1625
1488
+ U 3801 ; WX 910 ; N uni0ed9 ; G 1626
1489
+ U 3804 ; WX 1363 ; N uni0edc ; G 1627
1490
+ U 3805 ; WX 1363 ; N uni0edd ; G 1628
1491
+ U 4256 ; WX 918 ; N uni10a0 ; G 1629
1492
+ U 4257 ; WX 744 ; N uni10a1 ; G 1630
1493
+ U 4258 ; WX 739 ; N uni10a2 ; G 1631
1494
+ U 4259 ; WX 837 ; N uni10a3 ; G 1632
1495
+ U 4260 ; WX 649 ; N uni10a4 ; G 1633
1496
+ U 4261 ; WX 773 ; N uni10a5 ; G 1634
1497
+ U 4262 ; WX 857 ; N uni10a6 ; G 1635
1498
+ U 4263 ; WX 889 ; N uni10a7 ; G 1636
1499
+ U 4264 ; WX 530 ; N uni10a8 ; G 1637
1500
+ U 4265 ; WX 633 ; N uni10a9 ; G 1638
1501
+ U 4266 ; WX 857 ; N uni10aa ; G 1639
1502
+ U 4267 ; WX 900 ; N uni10ab ; G 1640
1503
+ U 4268 ; WX 643 ; N uni10ac ; G 1641
1504
+ U 4269 ; WX 903 ; N uni10ad ; G 1642
1505
+ U 4270 ; WX 814 ; N uni10ae ; G 1643
1506
+ U 4271 ; WX 752 ; N uni10af ; G 1644
1507
+ U 4272 ; WX 869 ; N uni10b0 ; G 1645
1508
+ U 4273 ; WX 643 ; N uni10b1 ; G 1646
1509
+ U 4274 ; WX 643 ; N uni10b2 ; G 1647
1510
+ U 4275 ; WX 886 ; N uni10b3 ; G 1648
1511
+ U 4276 ; WX 886 ; N uni10b4 ; G 1649
1512
+ U 4277 ; WX 733 ; N uni10b5 ; G 1650
1513
+ U 4278 ; WX 653 ; N uni10b6 ; G 1651
1514
+ U 4279 ; WX 643 ; N uni10b7 ; G 1652
1515
+ U 4280 ; WX 646 ; N uni10b8 ; G 1653
1516
+ U 4281 ; WX 643 ; N uni10b9 ; G 1654
1517
+ U 4282 ; WX 790 ; N uni10ba ; G 1655
1518
+ U 4283 ; WX 902 ; N uni10bb ; G 1656
1519
+ U 4284 ; WX 633 ; N uni10bc ; G 1657
1520
+ U 4285 ; WX 619 ; N uni10bd ; G 1658
1521
+ U 4286 ; WX 643 ; N uni10be ; G 1659
1522
+ U 4287 ; WX 778 ; N uni10bf ; G 1660
1523
+ U 4288 ; WX 892 ; N uni10c0 ; G 1661
1524
+ U 4289 ; WX 601 ; N uni10c1 ; G 1662
1525
+ U 4290 ; WX 742 ; N uni10c2 ; G 1663
1526
+ U 4291 ; WX 616 ; N uni10c3 ; G 1664
1527
+ U 4292 ; WX 633 ; N uni10c4 ; G 1665
1528
+ U 4293 ; WX 742 ; N uni10c5 ; G 1666
1529
+ U 4304 ; WX 553 ; N uni10d0 ; G 1667
1530
+ U 4305 ; WX 552 ; N uni10d1 ; G 1668
1531
+ U 4306 ; WX 596 ; N uni10d2 ; G 1669
1532
+ U 4307 ; WX 815 ; N uni10d3 ; G 1670
1533
+ U 4308 ; WX 562 ; N uni10d4 ; G 1671
1534
+ U 4309 ; WX 563 ; N uni10d5 ; G 1672
1535
+ U 4310 ; WX 553 ; N uni10d6 ; G 1673
1536
+ U 4311 ; WX 827 ; N uni10d7 ; G 1674
1537
+ U 4312 ; WX 553 ; N uni10d8 ; G 1675
1538
+ U 4313 ; WX 543 ; N uni10d9 ; G 1676
1539
+ U 4314 ; WX 1074 ; N uni10da ; G 1677
1540
+ U 4315 ; WX 563 ; N uni10db ; G 1678
1541
+ U 4316 ; WX 563 ; N uni10dc ; G 1679
1542
+ U 4317 ; WX 812 ; N uni10dd ; G 1680
1543
+ U 4318 ; WX 552 ; N uni10de ; G 1681
1544
+ U 4319 ; WX 591 ; N uni10df ; G 1682
1545
+ U 4320 ; WX 822 ; N uni10e0 ; G 1683
1546
+ U 4321 ; WX 563 ; N uni10e1 ; G 1684
1547
+ U 4322 ; WX 690 ; N uni10e2 ; G 1685
1548
+ U 4323 ; WX 583 ; N uni10e3 ; G 1686
1549
+ U 4324 ; WX 813 ; N uni10e4 ; G 1687
1550
+ U 4325 ; WX 562 ; N uni10e5 ; G 1688
1551
+ U 4326 ; WX 813 ; N uni10e6 ; G 1689
1552
+ U 4327 ; WX 563 ; N uni10e7 ; G 1690
1553
+ U 4328 ; WX 563 ; N uni10e8 ; G 1691
1554
+ U 4329 ; WX 563 ; N uni10e9 ; G 1692
1555
+ U 4330 ; WX 632 ; N uni10ea ; G 1693
1556
+ U 4331 ; WX 563 ; N uni10eb ; G 1694
1557
+ U 4332 ; WX 563 ; N uni10ec ; G 1695
1558
+ U 4333 ; WX 552 ; N uni10ed ; G 1696
1559
+ U 4334 ; WX 563 ; N uni10ee ; G 1697
1560
+ U 4335 ; WX 563 ; N uni10ef ; G 1698
1561
+ U 4336 ; WX 558 ; N uni10f0 ; G 1699
1562
+ U 4337 ; WX 604 ; N uni10f1 ; G 1700
1563
+ U 4338 ; WX 552 ; N uni10f2 ; G 1701
1564
+ U 4339 ; WX 552 ; N uni10f3 ; G 1702
1565
+ U 4340 ; WX 553 ; N uni10f4 ; G 1703
1566
+ U 4341 ; WX 605 ; N uni10f5 ; G 1704
1567
+ U 4342 ; WX 852 ; N uni10f6 ; G 1705
1568
+ U 4343 ; WX 635 ; N uni10f7 ; G 1706
1569
+ U 4344 ; WX 563 ; N uni10f8 ; G 1707
1570
+ U 4345 ; WX 596 ; N uni10f9 ; G 1708
1571
+ U 4346 ; WX 542 ; N uni10fa ; G 1709
1572
+ U 4347 ; WX 684 ; N uni10fb ; G 1710
1573
+ U 4348 ; WX 368 ; N uni10fc ; G 1711
1574
+ U 5121 ; WX 774 ; N uni1401 ; G 1712
1575
+ U 5122 ; WX 774 ; N uni1402 ; G 1713
1576
+ U 5123 ; WX 774 ; N uni1403 ; G 1714
1577
+ U 5124 ; WX 774 ; N uni1404 ; G 1715
1578
+ U 5125 ; WX 905 ; N uni1405 ; G 1716
1579
+ U 5126 ; WX 905 ; N uni1406 ; G 1717
1580
+ U 5127 ; WX 905 ; N uni1407 ; G 1718
1581
+ U 5129 ; WX 905 ; N uni1409 ; G 1719
1582
+ U 5130 ; WX 905 ; N uni140a ; G 1720
1583
+ U 5131 ; WX 905 ; N uni140b ; G 1721
1584
+ U 5132 ; WX 1018 ; N uni140c ; G 1722
1585
+ U 5133 ; WX 1009 ; N uni140d ; G 1723
1586
+ U 5134 ; WX 1018 ; N uni140e ; G 1724
1587
+ U 5135 ; WX 1009 ; N uni140f ; G 1725
1588
+ U 5136 ; WX 1018 ; N uni1410 ; G 1726
1589
+ U 5137 ; WX 1009 ; N uni1411 ; G 1727
1590
+ U 5138 ; WX 1149 ; N uni1412 ; G 1728
1591
+ U 5139 ; WX 1140 ; N uni1413 ; G 1729
1592
+ U 5140 ; WX 1149 ; N uni1414 ; G 1730
1593
+ U 5141 ; WX 1140 ; N uni1415 ; G 1731
1594
+ U 5142 ; WX 905 ; N uni1416 ; G 1732
1595
+ U 5143 ; WX 1149 ; N uni1417 ; G 1733
1596
+ U 5144 ; WX 1142 ; N uni1418 ; G 1734
1597
+ U 5145 ; WX 1149 ; N uni1419 ; G 1735
1598
+ U 5146 ; WX 1142 ; N uni141a ; G 1736
1599
+ U 5147 ; WX 905 ; N uni141b ; G 1737
1600
+ U 5149 ; WX 310 ; N uni141d ; G 1738
1601
+ U 5150 ; WX 529 ; N uni141e ; G 1739
1602
+ U 5151 ; WX 425 ; N uni141f ; G 1740
1603
+ U 5152 ; WX 425 ; N uni1420 ; G 1741
1604
+ U 5153 ; WX 395 ; N uni1421 ; G 1742
1605
+ U 5154 ; WX 395 ; N uni1422 ; G 1743
1606
+ U 5155 ; WX 395 ; N uni1423 ; G 1744
1607
+ U 5156 ; WX 395 ; N uni1424 ; G 1745
1608
+ U 5157 ; WX 564 ; N uni1425 ; G 1746
1609
+ U 5158 ; WX 470 ; N uni1426 ; G 1747
1610
+ U 5159 ; WX 310 ; N uni1427 ; G 1748
1611
+ U 5160 ; WX 395 ; N uni1428 ; G 1749
1612
+ U 5161 ; WX 395 ; N uni1429 ; G 1750
1613
+ U 5162 ; WX 395 ; N uni142a ; G 1751
1614
+ U 5163 ; WX 1213 ; N uni142b ; G 1752
1615
+ U 5164 ; WX 986 ; N uni142c ; G 1753
1616
+ U 5165 ; WX 1216 ; N uni142d ; G 1754
1617
+ U 5166 ; WX 1297 ; N uni142e ; G 1755
1618
+ U 5167 ; WX 774 ; N uni142f ; G 1756
1619
+ U 5168 ; WX 774 ; N uni1430 ; G 1757
1620
+ U 5169 ; WX 774 ; N uni1431 ; G 1758
1621
+ U 5170 ; WX 774 ; N uni1432 ; G 1759
1622
+ U 5171 ; WX 886 ; N uni1433 ; G 1760
1623
+ U 5172 ; WX 886 ; N uni1434 ; G 1761
1624
+ U 5173 ; WX 886 ; N uni1435 ; G 1762
1625
+ U 5175 ; WX 886 ; N uni1437 ; G 1763
1626
+ U 5176 ; WX 886 ; N uni1438 ; G 1764
1627
+ U 5177 ; WX 886 ; N uni1439 ; G 1765
1628
+ U 5178 ; WX 1018 ; N uni143a ; G 1766
1629
+ U 5179 ; WX 1009 ; N uni143b ; G 1767
1630
+ U 5180 ; WX 1018 ; N uni143c ; G 1768
1631
+ U 5181 ; WX 1009 ; N uni143d ; G 1769
1632
+ U 5182 ; WX 1018 ; N uni143e ; G 1770
1633
+ U 5183 ; WX 1009 ; N uni143f ; G 1771
1634
+ U 5184 ; WX 1149 ; N uni1440 ; G 1772
1635
+ U 5185 ; WX 1140 ; N uni1441 ; G 1773
1636
+ U 5186 ; WX 1149 ; N uni1442 ; G 1774
1637
+ U 5187 ; WX 1140 ; N uni1443 ; G 1775
1638
+ U 5188 ; WX 1149 ; N uni1444 ; G 1776
1639
+ U 5189 ; WX 1142 ; N uni1445 ; G 1777
1640
+ U 5190 ; WX 1149 ; N uni1446 ; G 1778
1641
+ U 5191 ; WX 1142 ; N uni1447 ; G 1779
1642
+ U 5192 ; WX 886 ; N uni1448 ; G 1780
1643
+ U 5193 ; WX 576 ; N uni1449 ; G 1781
1644
+ U 5194 ; WX 229 ; N uni144a ; G 1782
1645
+ U 5196 ; WX 812 ; N uni144c ; G 1783
1646
+ U 5197 ; WX 812 ; N uni144d ; G 1784
1647
+ U 5198 ; WX 812 ; N uni144e ; G 1785
1648
+ U 5199 ; WX 812 ; N uni144f ; G 1786
1649
+ U 5200 ; WX 815 ; N uni1450 ; G 1787
1650
+ U 5201 ; WX 815 ; N uni1451 ; G 1788
1651
+ U 5202 ; WX 815 ; N uni1452 ; G 1789
1652
+ U 5204 ; WX 815 ; N uni1454 ; G 1790
1653
+ U 5205 ; WX 815 ; N uni1455 ; G 1791
1654
+ U 5206 ; WX 815 ; N uni1456 ; G 1792
1655
+ U 5207 ; WX 1056 ; N uni1457 ; G 1793
1656
+ U 5208 ; WX 1048 ; N uni1458 ; G 1794
1657
+ U 5209 ; WX 1056 ; N uni1459 ; G 1795
1658
+ U 5210 ; WX 1048 ; N uni145a ; G 1796
1659
+ U 5211 ; WX 1056 ; N uni145b ; G 1797
1660
+ U 5212 ; WX 1048 ; N uni145c ; G 1798
1661
+ U 5213 ; WX 1060 ; N uni145d ; G 1799
1662
+ U 5214 ; WX 1054 ; N uni145e ; G 1800
1663
+ U 5215 ; WX 1060 ; N uni145f ; G 1801
1664
+ U 5216 ; WX 1054 ; N uni1460 ; G 1802
1665
+ U 5217 ; WX 1060 ; N uni1461 ; G 1803
1666
+ U 5218 ; WX 1052 ; N uni1462 ; G 1804
1667
+ U 5219 ; WX 1060 ; N uni1463 ; G 1805
1668
+ U 5220 ; WX 1052 ; N uni1464 ; G 1806
1669
+ U 5221 ; WX 1060 ; N uni1465 ; G 1807
1670
+ U 5222 ; WX 483 ; N uni1466 ; G 1808
1671
+ U 5223 ; WX 1005 ; N uni1467 ; G 1809
1672
+ U 5224 ; WX 1005 ; N uni1468 ; G 1810
1673
+ U 5225 ; WX 1023 ; N uni1469 ; G 1811
1674
+ U 5226 ; WX 1017 ; N uni146a ; G 1812
1675
+ U 5227 ; WX 743 ; N uni146b ; G 1813
1676
+ U 5228 ; WX 743 ; N uni146c ; G 1814
1677
+ U 5229 ; WX 743 ; N uni146d ; G 1815
1678
+ U 5230 ; WX 743 ; N uni146e ; G 1816
1679
+ U 5231 ; WX 743 ; N uni146f ; G 1817
1680
+ U 5232 ; WX 743 ; N uni1470 ; G 1818
1681
+ U 5233 ; WX 743 ; N uni1471 ; G 1819
1682
+ U 5234 ; WX 743 ; N uni1472 ; G 1820
1683
+ U 5235 ; WX 743 ; N uni1473 ; G 1821
1684
+ U 5236 ; WX 1029 ; N uni1474 ; G 1822
1685
+ U 5237 ; WX 975 ; N uni1475 ; G 1823
1686
+ U 5238 ; WX 980 ; N uni1476 ; G 1824
1687
+ U 5239 ; WX 975 ; N uni1477 ; G 1825
1688
+ U 5240 ; WX 980 ; N uni1478 ; G 1826
1689
+ U 5241 ; WX 975 ; N uni1479 ; G 1827
1690
+ U 5242 ; WX 1029 ; N uni147a ; G 1828
1691
+ U 5243 ; WX 975 ; N uni147b ; G 1829
1692
+ U 5244 ; WX 1029 ; N uni147c ; G 1830
1693
+ U 5245 ; WX 975 ; N uni147d ; G 1831
1694
+ U 5246 ; WX 980 ; N uni147e ; G 1832
1695
+ U 5247 ; WX 975 ; N uni147f ; G 1833
1696
+ U 5248 ; WX 980 ; N uni1480 ; G 1834
1697
+ U 5249 ; WX 975 ; N uni1481 ; G 1835
1698
+ U 5250 ; WX 980 ; N uni1482 ; G 1836
1699
+ U 5251 ; WX 501 ; N uni1483 ; G 1837
1700
+ U 5252 ; WX 501 ; N uni1484 ; G 1838
1701
+ U 5253 ; WX 938 ; N uni1485 ; G 1839
1702
+ U 5254 ; WX 938 ; N uni1486 ; G 1840
1703
+ U 5255 ; WX 938 ; N uni1487 ; G 1841
1704
+ U 5256 ; WX 938 ; N uni1488 ; G 1842
1705
+ U 5257 ; WX 743 ; N uni1489 ; G 1843
1706
+ U 5258 ; WX 743 ; N uni148a ; G 1844
1707
+ U 5259 ; WX 743 ; N uni148b ; G 1845
1708
+ U 5260 ; WX 743 ; N uni148c ; G 1846
1709
+ U 5261 ; WX 743 ; N uni148d ; G 1847
1710
+ U 5262 ; WX 743 ; N uni148e ; G 1848
1711
+ U 5263 ; WX 743 ; N uni148f ; G 1849
1712
+ U 5264 ; WX 743 ; N uni1490 ; G 1850
1713
+ U 5265 ; WX 743 ; N uni1491 ; G 1851
1714
+ U 5266 ; WX 1029 ; N uni1492 ; G 1852
1715
+ U 5267 ; WX 975 ; N uni1493 ; G 1853
1716
+ U 5268 ; WX 1029 ; N uni1494 ; G 1854
1717
+ U 5269 ; WX 975 ; N uni1495 ; G 1855
1718
+ U 5270 ; WX 1029 ; N uni1496 ; G 1856
1719
+ U 5271 ; WX 975 ; N uni1497 ; G 1857
1720
+ U 5272 ; WX 1029 ; N uni1498 ; G 1858
1721
+ U 5273 ; WX 975 ; N uni1499 ; G 1859
1722
+ U 5274 ; WX 1029 ; N uni149a ; G 1860
1723
+ U 5275 ; WX 975 ; N uni149b ; G 1861
1724
+ U 5276 ; WX 1029 ; N uni149c ; G 1862
1725
+ U 5277 ; WX 975 ; N uni149d ; G 1863
1726
+ U 5278 ; WX 1029 ; N uni149e ; G 1864
1727
+ U 5279 ; WX 975 ; N uni149f ; G 1865
1728
+ U 5280 ; WX 1029 ; N uni14a0 ; G 1866
1729
+ U 5281 ; WX 501 ; N uni14a1 ; G 1867
1730
+ U 5282 ; WX 501 ; N uni14a2 ; G 1868
1731
+ U 5283 ; WX 626 ; N uni14a3 ; G 1869
1732
+ U 5284 ; WX 626 ; N uni14a4 ; G 1870
1733
+ U 5285 ; WX 626 ; N uni14a5 ; G 1871
1734
+ U 5286 ; WX 626 ; N uni14a6 ; G 1872
1735
+ U 5287 ; WX 626 ; N uni14a7 ; G 1873
1736
+ U 5288 ; WX 626 ; N uni14a8 ; G 1874
1737
+ U 5289 ; WX 626 ; N uni14a9 ; G 1875
1738
+ U 5290 ; WX 626 ; N uni14aa ; G 1876
1739
+ U 5291 ; WX 626 ; N uni14ab ; G 1877
1740
+ U 5292 ; WX 881 ; N uni14ac ; G 1878
1741
+ U 5293 ; WX 854 ; N uni14ad ; G 1879
1742
+ U 5294 ; WX 863 ; N uni14ae ; G 1880
1743
+ U 5295 ; WX 874 ; N uni14af ; G 1881
1744
+ U 5296 ; WX 863 ; N uni14b0 ; G 1882
1745
+ U 5297 ; WX 874 ; N uni14b1 ; G 1883
1746
+ U 5298 ; WX 881 ; N uni14b2 ; G 1884
1747
+ U 5299 ; WX 874 ; N uni14b3 ; G 1885
1748
+ U 5300 ; WX 881 ; N uni14b4 ; G 1886
1749
+ U 5301 ; WX 874 ; N uni14b5 ; G 1887
1750
+ U 5302 ; WX 863 ; N uni14b6 ; G 1888
1751
+ U 5303 ; WX 874 ; N uni14b7 ; G 1889
1752
+ U 5304 ; WX 863 ; N uni14b8 ; G 1890
1753
+ U 5305 ; WX 874 ; N uni14b9 ; G 1891
1754
+ U 5306 ; WX 863 ; N uni14ba ; G 1892
1755
+ U 5307 ; WX 436 ; N uni14bb ; G 1893
1756
+ U 5308 ; WX 548 ; N uni14bc ; G 1894
1757
+ U 5309 ; WX 436 ; N uni14bd ; G 1895
1758
+ U 5312 ; WX 988 ; N uni14c0 ; G 1896
1759
+ U 5313 ; WX 988 ; N uni14c1 ; G 1897
1760
+ U 5314 ; WX 988 ; N uni14c2 ; G 1898
1761
+ U 5315 ; WX 988 ; N uni14c3 ; G 1899
1762
+ U 5316 ; WX 931 ; N uni14c4 ; G 1900
1763
+ U 5317 ; WX 931 ; N uni14c5 ; G 1901
1764
+ U 5318 ; WX 931 ; N uni14c6 ; G 1902
1765
+ U 5319 ; WX 931 ; N uni14c7 ; G 1903
1766
+ U 5320 ; WX 931 ; N uni14c8 ; G 1904
1767
+ U 5321 ; WX 1238 ; N uni14c9 ; G 1905
1768
+ U 5322 ; WX 1247 ; N uni14ca ; G 1906
1769
+ U 5323 ; WX 1200 ; N uni14cb ; G 1907
1770
+ U 5324 ; WX 1228 ; N uni14cc ; G 1908
1771
+ U 5325 ; WX 1200 ; N uni14cd ; G 1909
1772
+ U 5326 ; WX 1228 ; N uni14ce ; G 1910
1773
+ U 5327 ; WX 931 ; N uni14cf ; G 1911
1774
+ U 5328 ; WX 660 ; N uni14d0 ; G 1912
1775
+ U 5329 ; WX 497 ; N uni14d1 ; G 1913
1776
+ U 5330 ; WX 660 ; N uni14d2 ; G 1914
1777
+ U 5331 ; WX 988 ; N uni14d3 ; G 1915
1778
+ U 5332 ; WX 988 ; N uni14d4 ; G 1916
1779
+ U 5333 ; WX 988 ; N uni14d5 ; G 1917
1780
+ U 5334 ; WX 988 ; N uni14d6 ; G 1918
1781
+ U 5335 ; WX 931 ; N uni14d7 ; G 1919
1782
+ U 5336 ; WX 931 ; N uni14d8 ; G 1920
1783
+ U 5337 ; WX 931 ; N uni14d9 ; G 1921
1784
+ U 5338 ; WX 931 ; N uni14da ; G 1922
1785
+ U 5339 ; WX 931 ; N uni14db ; G 1923
1786
+ U 5340 ; WX 1231 ; N uni14dc ; G 1924
1787
+ U 5341 ; WX 1247 ; N uni14dd ; G 1925
1788
+ U 5342 ; WX 1283 ; N uni14de ; G 1926
1789
+ U 5343 ; WX 1228 ; N uni14df ; G 1927
1790
+ U 5344 ; WX 1283 ; N uni14e0 ; G 1928
1791
+ U 5345 ; WX 1228 ; N uni14e1 ; G 1929
1792
+ U 5346 ; WX 1228 ; N uni14e2 ; G 1930
1793
+ U 5347 ; WX 1214 ; N uni14e3 ; G 1931
1794
+ U 5348 ; WX 1228 ; N uni14e4 ; G 1932
1795
+ U 5349 ; WX 1214 ; N uni14e5 ; G 1933
1796
+ U 5350 ; WX 1283 ; N uni14e6 ; G 1934
1797
+ U 5351 ; WX 1228 ; N uni14e7 ; G 1935
1798
+ U 5352 ; WX 1283 ; N uni14e8 ; G 1936
1799
+ U 5353 ; WX 1228 ; N uni14e9 ; G 1937
1800
+ U 5354 ; WX 660 ; N uni14ea ; G 1938
1801
+ U 5356 ; WX 886 ; N uni14ec ; G 1939
1802
+ U 5357 ; WX 730 ; N uni14ed ; G 1940
1803
+ U 5358 ; WX 730 ; N uni14ee ; G 1941
1804
+ U 5359 ; WX 730 ; N uni14ef ; G 1942
1805
+ U 5360 ; WX 730 ; N uni14f0 ; G 1943
1806
+ U 5361 ; WX 730 ; N uni14f1 ; G 1944
1807
+ U 5362 ; WX 730 ; N uni14f2 ; G 1945
1808
+ U 5363 ; WX 730 ; N uni14f3 ; G 1946
1809
+ U 5364 ; WX 730 ; N uni14f4 ; G 1947
1810
+ U 5365 ; WX 730 ; N uni14f5 ; G 1948
1811
+ U 5366 ; WX 998 ; N uni14f6 ; G 1949
1812
+ U 5367 ; WX 958 ; N uni14f7 ; G 1950
1813
+ U 5368 ; WX 967 ; N uni14f8 ; G 1951
1814
+ U 5369 ; WX 989 ; N uni14f9 ; G 1952
1815
+ U 5370 ; WX 967 ; N uni14fa ; G 1953
1816
+ U 5371 ; WX 989 ; N uni14fb ; G 1954
1817
+ U 5372 ; WX 998 ; N uni14fc ; G 1955
1818
+ U 5373 ; WX 958 ; N uni14fd ; G 1956
1819
+ U 5374 ; WX 998 ; N uni14fe ; G 1957
1820
+ U 5375 ; WX 958 ; N uni14ff ; G 1958
1821
+ U 5376 ; WX 967 ; N uni1500 ; G 1959
1822
+ U 5377 ; WX 989 ; N uni1501 ; G 1960
1823
+ U 5378 ; WX 967 ; N uni1502 ; G 1961
1824
+ U 5379 ; WX 989 ; N uni1503 ; G 1962
1825
+ U 5380 ; WX 967 ; N uni1504 ; G 1963
1826
+ U 5381 ; WX 493 ; N uni1505 ; G 1964
1827
+ U 5382 ; WX 460 ; N uni1506 ; G 1965
1828
+ U 5383 ; WX 493 ; N uni1507 ; G 1966
1829
+ U 5392 ; WX 923 ; N uni1510 ; G 1967
1830
+ U 5393 ; WX 923 ; N uni1511 ; G 1968
1831
+ U 5394 ; WX 923 ; N uni1512 ; G 1969
1832
+ U 5395 ; WX 1136 ; N uni1513 ; G 1970
1833
+ U 5396 ; WX 1136 ; N uni1514 ; G 1971
1834
+ U 5397 ; WX 1136 ; N uni1515 ; G 1972
1835
+ U 5398 ; WX 1136 ; N uni1516 ; G 1973
1836
+ U 5399 ; WX 1209 ; N uni1517 ; G 1974
1837
+ U 5400 ; WX 1202 ; N uni1518 ; G 1975
1838
+ U 5401 ; WX 1209 ; N uni1519 ; G 1976
1839
+ U 5402 ; WX 1202 ; N uni151a ; G 1977
1840
+ U 5403 ; WX 1209 ; N uni151b ; G 1978
1841
+ U 5404 ; WX 1202 ; N uni151c ; G 1979
1842
+ U 5405 ; WX 1431 ; N uni151d ; G 1980
1843
+ U 5406 ; WX 1420 ; N uni151e ; G 1981
1844
+ U 5407 ; WX 1431 ; N uni151f ; G 1982
1845
+ U 5408 ; WX 1420 ; N uni1520 ; G 1983
1846
+ U 5409 ; WX 1431 ; N uni1521 ; G 1984
1847
+ U 5410 ; WX 1420 ; N uni1522 ; G 1985
1848
+ U 5411 ; WX 1431 ; N uni1523 ; G 1986
1849
+ U 5412 ; WX 1420 ; N uni1524 ; G 1987
1850
+ U 5413 ; WX 746 ; N uni1525 ; G 1988
1851
+ U 5414 ; WX 776 ; N uni1526 ; G 1989
1852
+ U 5415 ; WX 776 ; N uni1527 ; G 1990
1853
+ U 5416 ; WX 776 ; N uni1528 ; G 1991
1854
+ U 5417 ; WX 776 ; N uni1529 ; G 1992
1855
+ U 5418 ; WX 776 ; N uni152a ; G 1993
1856
+ U 5419 ; WX 776 ; N uni152b ; G 1994
1857
+ U 5420 ; WX 776 ; N uni152c ; G 1995
1858
+ U 5421 ; WX 776 ; N uni152d ; G 1996
1859
+ U 5422 ; WX 776 ; N uni152e ; G 1997
1860
+ U 5423 ; WX 1003 ; N uni152f ; G 1998
1861
+ U 5424 ; WX 1003 ; N uni1530 ; G 1999
1862
+ U 5425 ; WX 1013 ; N uni1531 ; G 2000
1863
+ U 5426 ; WX 996 ; N uni1532 ; G 2001
1864
+ U 5427 ; WX 1013 ; N uni1533 ; G 2002
1865
+ U 5428 ; WX 996 ; N uni1534 ; G 2003
1866
+ U 5429 ; WX 1003 ; N uni1535 ; G 2004
1867
+ U 5430 ; WX 1003 ; N uni1536 ; G 2005
1868
+ U 5431 ; WX 1003 ; N uni1537 ; G 2006
1869
+ U 5432 ; WX 1003 ; N uni1538 ; G 2007
1870
+ U 5433 ; WX 1013 ; N uni1539 ; G 2008
1871
+ U 5434 ; WX 996 ; N uni153a ; G 2009
1872
+ U 5435 ; WX 1013 ; N uni153b ; G 2010
1873
+ U 5436 ; WX 996 ; N uni153c ; G 2011
1874
+ U 5437 ; WX 1013 ; N uni153d ; G 2012
1875
+ U 5438 ; WX 495 ; N uni153e ; G 2013
1876
+ U 5440 ; WX 395 ; N uni1540 ; G 2014
1877
+ U 5441 ; WX 510 ; N uni1541 ; G 2015
1878
+ U 5442 ; WX 1033 ; N uni1542 ; G 2016
1879
+ U 5443 ; WX 1033 ; N uni1543 ; G 2017
1880
+ U 5444 ; WX 976 ; N uni1544 ; G 2018
1881
+ U 5445 ; WX 976 ; N uni1545 ; G 2019
1882
+ U 5446 ; WX 976 ; N uni1546 ; G 2020
1883
+ U 5447 ; WX 976 ; N uni1547 ; G 2021
1884
+ U 5448 ; WX 733 ; N uni1548 ; G 2022
1885
+ U 5449 ; WX 733 ; N uni1549 ; G 2023
1886
+ U 5450 ; WX 733 ; N uni154a ; G 2024
1887
+ U 5451 ; WX 733 ; N uni154b ; G 2025
1888
+ U 5452 ; WX 733 ; N uni154c ; G 2026
1889
+ U 5453 ; WX 733 ; N uni154d ; G 2027
1890
+ U 5454 ; WX 1003 ; N uni154e ; G 2028
1891
+ U 5455 ; WX 959 ; N uni154f ; G 2029
1892
+ U 5456 ; WX 495 ; N uni1550 ; G 2030
1893
+ U 5458 ; WX 886 ; N uni1552 ; G 2031
1894
+ U 5459 ; WX 774 ; N uni1553 ; G 2032
1895
+ U 5460 ; WX 774 ; N uni1554 ; G 2033
1896
+ U 5461 ; WX 774 ; N uni1555 ; G 2034
1897
+ U 5462 ; WX 774 ; N uni1556 ; G 2035
1898
+ U 5463 ; WX 928 ; N uni1557 ; G 2036
1899
+ U 5464 ; WX 928 ; N uni1558 ; G 2037
1900
+ U 5465 ; WX 928 ; N uni1559 ; G 2038
1901
+ U 5466 ; WX 928 ; N uni155a ; G 2039
1902
+ U 5467 ; WX 1172 ; N uni155b ; G 2040
1903
+ U 5468 ; WX 1142 ; N uni155c ; G 2041
1904
+ U 5469 ; WX 602 ; N uni155d ; G 2042
1905
+ U 5470 ; WX 812 ; N uni155e ; G 2043
1906
+ U 5471 ; WX 812 ; N uni155f ; G 2044
1907
+ U 5472 ; WX 812 ; N uni1560 ; G 2045
1908
+ U 5473 ; WX 812 ; N uni1561 ; G 2046
1909
+ U 5474 ; WX 812 ; N uni1562 ; G 2047
1910
+ U 5475 ; WX 812 ; N uni1563 ; G 2048
1911
+ U 5476 ; WX 815 ; N uni1564 ; G 2049
1912
+ U 5477 ; WX 815 ; N uni1565 ; G 2050
1913
+ U 5478 ; WX 815 ; N uni1566 ; G 2051
1914
+ U 5479 ; WX 815 ; N uni1567 ; G 2052
1915
+ U 5480 ; WX 1060 ; N uni1568 ; G 2053
1916
+ U 5481 ; WX 1052 ; N uni1569 ; G 2054
1917
+ U 5482 ; WX 548 ; N uni156a ; G 2055
1918
+ U 5492 ; WX 977 ; N uni1574 ; G 2056
1919
+ U 5493 ; WX 977 ; N uni1575 ; G 2057
1920
+ U 5494 ; WX 977 ; N uni1576 ; G 2058
1921
+ U 5495 ; WX 977 ; N uni1577 ; G 2059
1922
+ U 5496 ; WX 977 ; N uni1578 ; G 2060
1923
+ U 5497 ; WX 977 ; N uni1579 ; G 2061
1924
+ U 5498 ; WX 977 ; N uni157a ; G 2062
1925
+ U 5499 ; WX 618 ; N uni157b ; G 2063
1926
+ U 5500 ; WX 837 ; N uni157c ; G 2064
1927
+ U 5501 ; WX 510 ; N uni157d ; G 2065
1928
+ U 5502 ; WX 1238 ; N uni157e ; G 2066
1929
+ U 5503 ; WX 1238 ; N uni157f ; G 2067
1930
+ U 5504 ; WX 1238 ; N uni1580 ; G 2068
1931
+ U 5505 ; WX 1238 ; N uni1581 ; G 2069
1932
+ U 5506 ; WX 1238 ; N uni1582 ; G 2070
1933
+ U 5507 ; WX 1238 ; N uni1583 ; G 2071
1934
+ U 5508 ; WX 1238 ; N uni1584 ; G 2072
1935
+ U 5509 ; WX 989 ; N uni1585 ; G 2073
1936
+ U 5514 ; WX 977 ; N uni158a ; G 2074
1937
+ U 5515 ; WX 977 ; N uni158b ; G 2075
1938
+ U 5516 ; WX 977 ; N uni158c ; G 2076
1939
+ U 5517 ; WX 977 ; N uni158d ; G 2077
1940
+ U 5518 ; WX 1591 ; N uni158e ; G 2078
1941
+ U 5519 ; WX 1591 ; N uni158f ; G 2079
1942
+ U 5520 ; WX 1591 ; N uni1590 ; G 2080
1943
+ U 5521 ; WX 1295 ; N uni1591 ; G 2081
1944
+ U 5522 ; WX 1295 ; N uni1592 ; G 2082
1945
+ U 5523 ; WX 1591 ; N uni1593 ; G 2083
1946
+ U 5524 ; WX 1591 ; N uni1594 ; G 2084
1947
+ U 5525 ; WX 848 ; N uni1595 ; G 2085
1948
+ U 5526 ; WX 1273 ; N uni1596 ; G 2086
1949
+ U 5536 ; WX 988 ; N uni15a0 ; G 2087
1950
+ U 5537 ; WX 988 ; N uni15a1 ; G 2088
1951
+ U 5538 ; WX 931 ; N uni15a2 ; G 2089
1952
+ U 5539 ; WX 931 ; N uni15a3 ; G 2090
1953
+ U 5540 ; WX 931 ; N uni15a4 ; G 2091
1954
+ U 5541 ; WX 931 ; N uni15a5 ; G 2092
1955
+ U 5542 ; WX 660 ; N uni15a6 ; G 2093
1956
+ U 5543 ; WX 776 ; N uni15a7 ; G 2094
1957
+ U 5544 ; WX 776 ; N uni15a8 ; G 2095
1958
+ U 5545 ; WX 776 ; N uni15a9 ; G 2096
1959
+ U 5546 ; WX 776 ; N uni15aa ; G 2097
1960
+ U 5547 ; WX 776 ; N uni15ab ; G 2098
1961
+ U 5548 ; WX 776 ; N uni15ac ; G 2099
1962
+ U 5549 ; WX 776 ; N uni15ad ; G 2100
1963
+ U 5550 ; WX 495 ; N uni15ae ; G 2101
1964
+ U 5551 ; WX 743 ; N uni15af ; G 2102
1965
+ U 5598 ; WX 830 ; N uni15de ; G 2103
1966
+ U 5601 ; WX 830 ; N uni15e1 ; G 2104
1967
+ U 5702 ; WX 496 ; N uni1646 ; G 2105
1968
+ U 5703 ; WX 496 ; N uni1647 ; G 2106
1969
+ U 5742 ; WX 413 ; N uni166e ; G 2107
1970
+ U 5743 ; WX 1238 ; N uni166f ; G 2108
1971
+ U 5744 ; WX 1591 ; N uni1670 ; G 2109
1972
+ U 5745 ; WX 2016 ; N uni1671 ; G 2110
1973
+ U 5746 ; WX 2016 ; N uni1672 ; G 2111
1974
+ U 5747 ; WX 1720 ; N uni1673 ; G 2112
1975
+ U 5748 ; WX 1678 ; N uni1674 ; G 2113
1976
+ U 5749 ; WX 2016 ; N uni1675 ; G 2114
1977
+ U 5750 ; WX 2016 ; N uni1676 ; G 2115
1978
+ U 5760 ; WX 543 ; N uni1680 ; G 2116
1979
+ U 5761 ; WX 637 ; N uni1681 ; G 2117
1980
+ U 5762 ; WX 945 ; N uni1682 ; G 2118
1981
+ U 5763 ; WX 1254 ; N uni1683 ; G 2119
1982
+ U 5764 ; WX 1563 ; N uni1684 ; G 2120
1983
+ U 5765 ; WX 1871 ; N uni1685 ; G 2121
1984
+ U 5766 ; WX 627 ; N uni1686 ; G 2122
1985
+ U 5767 ; WX 936 ; N uni1687 ; G 2123
1986
+ U 5768 ; WX 1254 ; N uni1688 ; G 2124
1987
+ U 5769 ; WX 1559 ; N uni1689 ; G 2125
1988
+ U 5770 ; WX 1871 ; N uni168a ; G 2126
1989
+ U 5771 ; WX 569 ; N uni168b ; G 2127
1990
+ U 5772 ; WX 877 ; N uni168c ; G 2128
1991
+ U 5773 ; WX 1187 ; N uni168d ; G 2129
1992
+ U 5774 ; WX 1497 ; N uni168e ; G 2130
1993
+ U 5775 ; WX 1807 ; N uni168f ; G 2131
1994
+ U 5776 ; WX 637 ; N uni1690 ; G 2132
1995
+ U 5777 ; WX 945 ; N uni1691 ; G 2133
1996
+ U 5778 ; WX 1240 ; N uni1692 ; G 2134
1997
+ U 5779 ; WX 1555 ; N uni1693 ; G 2135
1998
+ U 5780 ; WX 1871 ; N uni1694 ; G 2136
1999
+ U 5781 ; WX 569 ; N uni1695 ; G 2137
2000
+ U 5782 ; WX 569 ; N uni1696 ; G 2138
2001
+ U 5783 ; WX 789 ; N uni1697 ; G 2139
2002
+ U 5784 ; WX 1234 ; N uni1698 ; G 2140
2003
+ U 5785 ; WX 1559 ; N uni1699 ; G 2141
2004
+ U 5786 ; WX 740 ; N uni169a ; G 2142
2005
+ U 5787 ; WX 638 ; N uni169b ; G 2143
2006
+ U 5788 ; WX 638 ; N uni169c ; G 2144
2007
+ U 7424 ; WX 652 ; N uni1d00 ; G 2145
2008
+ U 7425 ; WX 833 ; N uni1d01 ; G 2146
2009
+ U 7426 ; WX 1048 ; N uni1d02 ; G 2147
2010
+ U 7427 ; WX 608 ; N uni1d03 ; G 2148
2011
+ U 7428 ; WX 593 ; N uni1d04 ; G 2149
2012
+ U 7429 ; WX 676 ; N uni1d05 ; G 2150
2013
+ U 7430 ; WX 676 ; N uni1d06 ; G 2151
2014
+ U 7431 ; WX 559 ; N uni1d07 ; G 2152
2015
+ U 7432 ; WX 557 ; N uni1d08 ; G 2153
2016
+ U 7433 ; WX 343 ; N uni1d09 ; G 2154
2017
+ U 7434 ; WX 494 ; N uni1d0a ; G 2155
2018
+ U 7435 ; WX 665 ; N uni1d0b ; G 2156
2019
+ U 7436 ; WX 539 ; N uni1d0c ; G 2157
2020
+ U 7437 ; WX 817 ; N uni1d0d ; G 2158
2021
+ U 7438 ; WX 701 ; N uni1d0e ; G 2159
2022
+ U 7439 ; WX 687 ; N uni1d0f ; G 2160
2023
+ U 7440 ; WX 593 ; N uni1d10 ; G 2161
2024
+ U 7441 ; WX 660 ; N uni1d11 ; G 2162
2025
+ U 7442 ; WX 660 ; N uni1d12 ; G 2163
2026
+ U 7443 ; WX 660 ; N uni1d13 ; G 2164
2027
+ U 7444 ; WX 1094 ; N uni1d14 ; G 2165
2028
+ U 7446 ; WX 687 ; N uni1d16 ; G 2166
2029
+ U 7447 ; WX 687 ; N uni1d17 ; G 2167
2030
+ U 7448 ; WX 556 ; N uni1d18 ; G 2168
2031
+ U 7449 ; WX 642 ; N uni1d19 ; G 2169
2032
+ U 7450 ; WX 642 ; N uni1d1a ; G 2170
2033
+ U 7451 ; WX 580 ; N uni1d1b ; G 2171
2034
+ U 7452 ; WX 634 ; N uni1d1c ; G 2172
2035
+ U 7453 ; WX 737 ; N uni1d1d ; G 2173
2036
+ U 7454 ; WX 948 ; N uni1d1e ; G 2174
2037
+ U 7455 ; WX 695 ; N uni1d1f ; G 2175
2038
+ U 7456 ; WX 652 ; N uni1d20 ; G 2176
2039
+ U 7457 ; WX 924 ; N uni1d21 ; G 2177
2040
+ U 7458 ; WX 582 ; N uni1d22 ; G 2178
2041
+ U 7459 ; WX 646 ; N uni1d23 ; G 2179
2042
+ U 7462 ; WX 539 ; N uni1d26 ; G 2180
2043
+ U 7463 ; WX 652 ; N uni1d27 ; G 2181
2044
+ U 7464 ; WX 691 ; N uni1d28 ; G 2182
2045
+ U 7465 ; WX 556 ; N uni1d29 ; G 2183
2046
+ U 7466 ; WX 781 ; N uni1d2a ; G 2184
2047
+ U 7467 ; WX 732 ; N uni1d2b ; G 2185
2048
+ U 7468 ; WX 487 ; N uni1d2c ; G 2186
2049
+ U 7469 ; WX 683 ; N uni1d2d ; G 2187
2050
+ U 7470 ; WX 480 ; N uni1d2e ; G 2188
2051
+ U 7472 ; WX 523 ; N uni1d30 ; G 2189
2052
+ U 7473 ; WX 430 ; N uni1d31 ; G 2190
2053
+ U 7474 ; WX 430 ; N uni1d32 ; G 2191
2054
+ U 7475 ; WX 517 ; N uni1d33 ; G 2192
2055
+ U 7476 ; WX 527 ; N uni1d34 ; G 2193
2056
+ U 7477 ; WX 234 ; N uni1d35 ; G 2194
2057
+ U 7478 ; WX 234 ; N uni1d36 ; G 2195
2058
+ U 7479 ; WX 488 ; N uni1d37 ; G 2196
2059
+ U 7480 ; WX 401 ; N uni1d38 ; G 2197
2060
+ U 7481 ; WX 626 ; N uni1d39 ; G 2198
2061
+ U 7482 ; WX 527 ; N uni1d3a ; G 2199
2062
+ U 7483 ; WX 527 ; N uni1d3b ; G 2200
2063
+ U 7484 ; WX 535 ; N uni1d3c ; G 2201
2064
+ U 7485 ; WX 509 ; N uni1d3d ; G 2202
2065
+ U 7486 ; WX 461 ; N uni1d3e ; G 2203
2066
+ U 7487 ; WX 485 ; N uni1d3f ; G 2204
2067
+ U 7488 ; WX 430 ; N uni1d40 ; G 2205
2068
+ U 7489 ; WX 511 ; N uni1d41 ; G 2206
2069
+ U 7490 ; WX 695 ; N uni1d42 ; G 2207
2070
+ U 7491 ; WX 458 ; N uni1d43 ; G 2208
2071
+ U 7492 ; WX 458 ; N uni1d44 ; G 2209
2072
+ U 7493 ; WX 479 ; N uni1d45 ; G 2210
2073
+ U 7494 ; WX 712 ; N uni1d46 ; G 2211
2074
+ U 7495 ; WX 479 ; N uni1d47 ; G 2212
2075
+ U 7496 ; WX 479 ; N uni1d48 ; G 2213
2076
+ U 7497 ; WX 479 ; N uni1d49 ; G 2214
2077
+ U 7498 ; WX 479 ; N uni1d4a ; G 2215
2078
+ U 7499 ; WX 386 ; N uni1d4b ; G 2216
2079
+ U 7500 ; WX 386 ; N uni1d4c ; G 2217
2080
+ U 7501 ; WX 479 ; N uni1d4d ; G 2218
2081
+ U 7502 ; WX 219 ; N uni1d4e ; G 2219
2082
+ U 7503 ; WX 487 ; N uni1d4f ; G 2220
2083
+ U 7504 ; WX 664 ; N uni1d50 ; G 2221
2084
+ U 7505 ; WX 456 ; N uni1d51 ; G 2222
2085
+ U 7506 ; WX 488 ; N uni1d52 ; G 2223
2086
+ U 7507 ; WX 414 ; N uni1d53 ; G 2224
2087
+ U 7508 ; WX 488 ; N uni1d54 ; G 2225
2088
+ U 7509 ; WX 488 ; N uni1d55 ; G 2226
2089
+ U 7510 ; WX 479 ; N uni1d56 ; G 2227
2090
+ U 7511 ; WX 388 ; N uni1d57 ; G 2228
2091
+ U 7512 ; WX 456 ; N uni1d58 ; G 2229
2092
+ U 7513 ; WX 462 ; N uni1d59 ; G 2230
2093
+ U 7514 ; WX 664 ; N uni1d5a ; G 2231
2094
+ U 7515 ; WX 501 ; N uni1d5b ; G 2232
2095
+ U 7517 ; WX 451 ; N uni1d5d ; G 2233
2096
+ U 7518 ; WX 429 ; N uni1d5e ; G 2234
2097
+ U 7519 ; WX 433 ; N uni1d5f ; G 2235
2098
+ U 7520 ; WX 493 ; N uni1d60 ; G 2236
2099
+ U 7521 ; WX 406 ; N uni1d61 ; G 2237
2100
+ U 7522 ; WX 219 ; N uni1d62 ; G 2238
2101
+ U 7523 ; WX 315 ; N uni1d63 ; G 2239
2102
+ U 7524 ; WX 456 ; N uni1d64 ; G 2240
2103
+ U 7525 ; WX 501 ; N uni1d65 ; G 2241
2104
+ U 7526 ; WX 451 ; N uni1d66 ; G 2242
2105
+ U 7527 ; WX 429 ; N uni1d67 ; G 2243
2106
+ U 7528 ; WX 451 ; N uni1d68 ; G 2244
2107
+ U 7529 ; WX 493 ; N uni1d69 ; G 2245
2108
+ U 7530 ; WX 406 ; N uni1d6a ; G 2246
2109
+ U 7543 ; WX 716 ; N uni1d77 ; G 2247
2110
+ U 7544 ; WX 527 ; N uni1d78 ; G 2248
2111
+ U 7547 ; WX 545 ; N uni1d7b ; G 2249
2112
+ U 7549 ; WX 747 ; N uni1d7d ; G 2250
2113
+ U 7557 ; WX 514 ; N uni1d85 ; G 2251
2114
+ U 7579 ; WX 479 ; N uni1d9b ; G 2252
2115
+ U 7580 ; WX 414 ; N uni1d9c ; G 2253
2116
+ U 7581 ; WX 414 ; N uni1d9d ; G 2254
2117
+ U 7582 ; WX 488 ; N uni1d9e ; G 2255
2118
+ U 7583 ; WX 386 ; N uni1d9f ; G 2256
2119
+ U 7584 ; WX 377 ; N uni1da0 ; G 2257
2120
+ U 7585 ; WX 348 ; N uni1da1 ; G 2258
2121
+ U 7586 ; WX 479 ; N uni1da2 ; G 2259
2122
+ U 7587 ; WX 456 ; N uni1da3 ; G 2260
2123
+ U 7588 ; WX 347 ; N uni1da4 ; G 2261
2124
+ U 7589 ; WX 281 ; N uni1da5 ; G 2262
2125
+ U 7590 ; WX 347 ; N uni1da6 ; G 2263
2126
+ U 7591 ; WX 347 ; N uni1da7 ; G 2264
2127
+ U 7592 ; WX 431 ; N uni1da8 ; G 2265
2128
+ U 7593 ; WX 326 ; N uni1da9 ; G 2266
2129
+ U 7594 ; WX 330 ; N uni1daa ; G 2267
2130
+ U 7595 ; WX 370 ; N uni1dab ; G 2268
2131
+ U 7596 ; WX 664 ; N uni1dac ; G 2269
2132
+ U 7597 ; WX 664 ; N uni1dad ; G 2270
2133
+ U 7598 ; WX 562 ; N uni1dae ; G 2271
2134
+ U 7599 ; WX 562 ; N uni1daf ; G 2272
2135
+ U 7600 ; WX 448 ; N uni1db0 ; G 2273
2136
+ U 7601 ; WX 488 ; N uni1db1 ; G 2274
2137
+ U 7602 ; WX 542 ; N uni1db2 ; G 2275
2138
+ U 7603 ; WX 422 ; N uni1db3 ; G 2276
2139
+ U 7604 ; WX 396 ; N uni1db4 ; G 2277
2140
+ U 7605 ; WX 388 ; N uni1db5 ; G 2278
2141
+ U 7606 ; WX 583 ; N uni1db6 ; G 2279
2142
+ U 7607 ; WX 494 ; N uni1db7 ; G 2280
2143
+ U 7608 ; WX 399 ; N uni1db8 ; G 2281
2144
+ U 7609 ; WX 451 ; N uni1db9 ; G 2282
2145
+ U 7610 ; WX 501 ; N uni1dba ; G 2283
2146
+ U 7611 ; WX 417 ; N uni1dbb ; G 2284
2147
+ U 7612 ; WX 523 ; N uni1dbc ; G 2285
2148
+ U 7613 ; WX 470 ; N uni1dbd ; G 2286
2149
+ U 7614 ; WX 455 ; N uni1dbe ; G 2287
2150
+ U 7615 ; WX 425 ; N uni1dbf ; G 2288
2151
+ U 7680 ; WX 774 ; N uni1e00 ; G 2295
2152
+ U 7681 ; WX 675 ; N uni1e01 ; G 2296
2153
+ U 7682 ; WX 762 ; N uni1e02 ; G 2297
2154
+ U 7683 ; WX 716 ; N uni1e03 ; G 2298
2155
+ U 7684 ; WX 762 ; N uni1e04 ; G 2299
2156
+ U 7685 ; WX 716 ; N uni1e05 ; G 2300
2157
+ U 7686 ; WX 762 ; N uni1e06 ; G 2301
2158
+ U 7687 ; WX 716 ; N uni1e07 ; G 2302
2159
+ U 7688 ; WX 734 ; N uni1e08 ; G 2303
2160
+ U 7689 ; WX 593 ; N uni1e09 ; G 2304
2161
+ U 7690 ; WX 830 ; N uni1e0a ; G 2305
2162
+ U 7691 ; WX 716 ; N uni1e0b ; G 2306
2163
+ U 7692 ; WX 830 ; N uni1e0c ; G 2307
2164
+ U 7693 ; WX 716 ; N uni1e0d ; G 2308
2165
+ U 7694 ; WX 830 ; N uni1e0e ; G 2309
2166
+ U 7695 ; WX 716 ; N uni1e0f ; G 2310
2167
+ U 7696 ; WX 830 ; N uni1e10 ; G 2311
2168
+ U 7697 ; WX 716 ; N uni1e11 ; G 2312
2169
+ U 7698 ; WX 830 ; N uni1e12 ; G 2313
2170
+ U 7699 ; WX 716 ; N uni1e13 ; G 2314
2171
+ U 7700 ; WX 683 ; N uni1e14 ; G 2315
2172
+ U 7701 ; WX 678 ; N uni1e15 ; G 2316
2173
+ U 7702 ; WX 683 ; N uni1e16 ; G 2317
2174
+ U 7703 ; WX 678 ; N uni1e17 ; G 2318
2175
+ U 7704 ; WX 683 ; N uni1e18 ; G 2319
2176
+ U 7705 ; WX 678 ; N uni1e19 ; G 2320
2177
+ U 7706 ; WX 683 ; N uni1e1a ; G 2321
2178
+ U 7707 ; WX 678 ; N uni1e1b ; G 2322
2179
+ U 7708 ; WX 683 ; N uni1e1c ; G 2323
2180
+ U 7709 ; WX 678 ; N uni1e1d ; G 2324
2181
+ U 7710 ; WX 683 ; N uni1e1e ; G 2325
2182
+ U 7711 ; WX 435 ; N uni1e1f ; G 2326
2183
+ U 7712 ; WX 821 ; N uni1e20 ; G 2327
2184
+ U 7713 ; WX 716 ; N uni1e21 ; G 2328
2185
+ U 7714 ; WX 837 ; N uni1e22 ; G 2329
2186
+ U 7715 ; WX 712 ; N uni1e23 ; G 2330
2187
+ U 7716 ; WX 837 ; N uni1e24 ; G 2331
2188
+ U 7717 ; WX 712 ; N uni1e25 ; G 2332
2189
+ U 7718 ; WX 837 ; N uni1e26 ; G 2333
2190
+ U 7719 ; WX 712 ; N uni1e27 ; G 2334
2191
+ U 7720 ; WX 837 ; N uni1e28 ; G 2335
2192
+ U 7721 ; WX 712 ; N uni1e29 ; G 2336
2193
+ U 7722 ; WX 837 ; N uni1e2a ; G 2337
2194
+ U 7723 ; WX 712 ; N uni1e2b ; G 2338
2195
+ U 7724 ; WX 372 ; N uni1e2c ; G 2339
2196
+ U 7725 ; WX 343 ; N uni1e2d ; G 2340
2197
+ U 7726 ; WX 372 ; N uni1e2e ; G 2341
2198
+ U 7727 ; WX 343 ; N uni1e2f ; G 2342
2199
+ U 7728 ; WX 775 ; N uni1e30 ; G 2343
2200
+ U 7729 ; WX 665 ; N uni1e31 ; G 2344
2201
+ U 7730 ; WX 775 ; N uni1e32 ; G 2345
2202
+ U 7731 ; WX 665 ; N uni1e33 ; G 2346
2203
+ U 7732 ; WX 775 ; N uni1e34 ; G 2347
2204
+ U 7733 ; WX 665 ; N uni1e35 ; G 2348
2205
+ U 7734 ; WX 637 ; N uni1e36 ; G 2349
2206
+ U 7735 ; WX 343 ; N uni1e37 ; G 2350
2207
+ U 7736 ; WX 637 ; N uni1e38 ; G 2351
2208
+ U 7737 ; WX 343 ; N uni1e39 ; G 2352
2209
+ U 7738 ; WX 637 ; N uni1e3a ; G 2353
2210
+ U 7739 ; WX 343 ; N uni1e3b ; G 2354
2211
+ U 7740 ; WX 637 ; N uni1e3c ; G 2355
2212
+ U 7741 ; WX 343 ; N uni1e3d ; G 2356
2213
+ U 7742 ; WX 995 ; N uni1e3e ; G 2357
2214
+ U 7743 ; WX 1042 ; N uni1e3f ; G 2358
2215
+ U 7744 ; WX 995 ; N uni1e40 ; G 2359
2216
+ U 7745 ; WX 1042 ; N uni1e41 ; G 2360
2217
+ U 7746 ; WX 995 ; N uni1e42 ; G 2361
2218
+ U 7747 ; WX 1042 ; N uni1e43 ; G 2362
2219
+ U 7748 ; WX 837 ; N uni1e44 ; G 2363
2220
+ U 7749 ; WX 712 ; N uni1e45 ; G 2364
2221
+ U 7750 ; WX 837 ; N uni1e46 ; G 2365
2222
+ U 7751 ; WX 712 ; N uni1e47 ; G 2366
2223
+ U 7752 ; WX 837 ; N uni1e48 ; G 2367
2224
+ U 7753 ; WX 712 ; N uni1e49 ; G 2368
2225
+ U 7754 ; WX 837 ; N uni1e4a ; G 2369
2226
+ U 7755 ; WX 712 ; N uni1e4b ; G 2370
2227
+ U 7756 ; WX 850 ; N uni1e4c ; G 2371
2228
+ U 7757 ; WX 687 ; N uni1e4d ; G 2372
2229
+ U 7758 ; WX 850 ; N uni1e4e ; G 2373
2230
+ U 7759 ; WX 687 ; N uni1e4f ; G 2374
2231
+ U 7760 ; WX 850 ; N uni1e50 ; G 2375
2232
+ U 7761 ; WX 687 ; N uni1e51 ; G 2376
2233
+ U 7762 ; WX 850 ; N uni1e52 ; G 2377
2234
+ U 7763 ; WX 687 ; N uni1e53 ; G 2378
2235
+ U 7764 ; WX 733 ; N uni1e54 ; G 2379
2236
+ U 7765 ; WX 716 ; N uni1e55 ; G 2380
2237
+ U 7766 ; WX 733 ; N uni1e56 ; G 2381
2238
+ U 7767 ; WX 716 ; N uni1e57 ; G 2382
2239
+ U 7768 ; WX 770 ; N uni1e58 ; G 2383
2240
+ U 7769 ; WX 493 ; N uni1e59 ; G 2384
2241
+ U 7770 ; WX 770 ; N uni1e5a ; G 2385
2242
+ U 7771 ; WX 493 ; N uni1e5b ; G 2386
2243
+ U 7772 ; WX 770 ; N uni1e5c ; G 2387
2244
+ U 7773 ; WX 493 ; N uni1e5d ; G 2388
2245
+ U 7774 ; WX 770 ; N uni1e5e ; G 2389
2246
+ U 7775 ; WX 493 ; N uni1e5f ; G 2390
2247
+ U 7776 ; WX 720 ; N uni1e60 ; G 2391
2248
+ U 7777 ; WX 595 ; N uni1e61 ; G 2392
2249
+ U 7778 ; WX 720 ; N uni1e62 ; G 2393
2250
+ U 7779 ; WX 595 ; N uni1e63 ; G 2394
2251
+ U 7780 ; WX 720 ; N uni1e64 ; G 2395
2252
+ U 7781 ; WX 595 ; N uni1e65 ; G 2396
2253
+ U 7782 ; WX 720 ; N uni1e66 ; G 2397
2254
+ U 7783 ; WX 595 ; N uni1e67 ; G 2398
2255
+ U 7784 ; WX 720 ; N uni1e68 ; G 2399
2256
+ U 7785 ; WX 595 ; N uni1e69 ; G 2400
2257
+ U 7786 ; WX 682 ; N uni1e6a ; G 2401
2258
+ U 7787 ; WX 478 ; N uni1e6b ; G 2402
2259
+ U 7788 ; WX 682 ; N uni1e6c ; G 2403
2260
+ U 7789 ; WX 478 ; N uni1e6d ; G 2404
2261
+ U 7790 ; WX 682 ; N uni1e6e ; G 2405
2262
+ U 7791 ; WX 478 ; N uni1e6f ; G 2406
2263
+ U 7792 ; WX 682 ; N uni1e70 ; G 2407
2264
+ U 7793 ; WX 478 ; N uni1e71 ; G 2408
2265
+ U 7794 ; WX 812 ; N uni1e72 ; G 2409
2266
+ U 7795 ; WX 712 ; N uni1e73 ; G 2410
2267
+ U 7796 ; WX 812 ; N uni1e74 ; G 2411
2268
+ U 7797 ; WX 712 ; N uni1e75 ; G 2412
2269
+ U 7798 ; WX 812 ; N uni1e76 ; G 2413
2270
+ U 7799 ; WX 712 ; N uni1e77 ; G 2414
2271
+ U 7800 ; WX 812 ; N uni1e78 ; G 2415
2272
+ U 7801 ; WX 712 ; N uni1e79 ; G 2416
2273
+ U 7802 ; WX 812 ; N uni1e7a ; G 2417
2274
+ U 7803 ; WX 712 ; N uni1e7b ; G 2418
2275
+ U 7804 ; WX 774 ; N uni1e7c ; G 2419
2276
+ U 7805 ; WX 652 ; N uni1e7d ; G 2420
2277
+ U 7806 ; WX 774 ; N uni1e7e ; G 2421
2278
+ U 7807 ; WX 652 ; N uni1e7f ; G 2422
2279
+ U 7808 ; WX 1103 ; N uni1e80 ; G 2423
2280
+ U 7809 ; WX 924 ; N uni1e81 ; G 2424
2281
+ U 7810 ; WX 1103 ; N uni1e82 ; G 2425
2282
+ U 7811 ; WX 924 ; N uni1e83 ; G 2426
2283
+ U 7812 ; WX 1103 ; N uni1e84 ; G 2427
2284
+ U 7813 ; WX 924 ; N uni1e85 ; G 2428
2285
+ U 7814 ; WX 1103 ; N uni1e86 ; G 2429
2286
+ U 7815 ; WX 924 ; N uni1e87 ; G 2430
2287
+ U 7816 ; WX 1103 ; N uni1e88 ; G 2431
2288
+ U 7817 ; WX 924 ; N uni1e89 ; G 2432
2289
+ U 7818 ; WX 771 ; N uni1e8a ; G 2433
2290
+ U 7819 ; WX 645 ; N uni1e8b ; G 2434
2291
+ U 7820 ; WX 771 ; N uni1e8c ; G 2435
2292
+ U 7821 ; WX 645 ; N uni1e8d ; G 2436
2293
+ U 7822 ; WX 724 ; N uni1e8e ; G 2437
2294
+ U 7823 ; WX 652 ; N uni1e8f ; G 2438
2295
+ U 7824 ; WX 725 ; N uni1e90 ; G 2439
2296
+ U 7825 ; WX 582 ; N uni1e91 ; G 2440
2297
+ U 7826 ; WX 725 ; N uni1e92 ; G 2441
2298
+ U 7827 ; WX 582 ; N uni1e93 ; G 2442
2299
+ U 7828 ; WX 725 ; N uni1e94 ; G 2443
2300
+ U 7829 ; WX 582 ; N uni1e95 ; G 2444
2301
+ U 7830 ; WX 712 ; N uni1e96 ; G 2445
2302
+ U 7831 ; WX 478 ; N uni1e97 ; G 2446
2303
+ U 7832 ; WX 924 ; N uni1e98 ; G 2447
2304
+ U 7833 ; WX 652 ; N uni1e99 ; G 2448
2305
+ U 7834 ; WX 675 ; N uni1e9a ; G 2449
2306
+ U 7835 ; WX 435 ; N uni1e9b ; G 2450
2307
+ U 7836 ; WX 435 ; N uni1e9c ; G 2451
2308
+ U 7837 ; WX 435 ; N uni1e9d ; G 2452
2309
+ U 7838 ; WX 896 ; N uni1e9e ; G 2453
2310
+ U 7839 ; WX 687 ; N uni1e9f ; G 2454
2311
+ U 7840 ; WX 774 ; N uni1ea0 ; G 2455
2312
+ U 7841 ; WX 675 ; N uni1ea1 ; G 2456
2313
+ U 7842 ; WX 774 ; N uni1ea2 ; G 2457
2314
+ U 7843 ; WX 675 ; N uni1ea3 ; G 2458
2315
+ U 7844 ; WX 774 ; N uni1ea4 ; G 2459
2316
+ U 7845 ; WX 675 ; N uni1ea5 ; G 2460
2317
+ U 7846 ; WX 774 ; N uni1ea6 ; G 2461
2318
+ U 7847 ; WX 675 ; N uni1ea7 ; G 2462
2319
+ U 7848 ; WX 774 ; N uni1ea8 ; G 2463
2320
+ U 7849 ; WX 675 ; N uni1ea9 ; G 2464
2321
+ U 7850 ; WX 774 ; N uni1eaa ; G 2465
2322
+ U 7851 ; WX 675 ; N uni1eab ; G 2466
2323
+ U 7852 ; WX 774 ; N uni1eac ; G 2467
2324
+ U 7853 ; WX 675 ; N uni1ead ; G 2468
2325
+ U 7854 ; WX 774 ; N uni1eae ; G 2469
2326
+ U 7855 ; WX 675 ; N uni1eaf ; G 2470
2327
+ U 7856 ; WX 774 ; N uni1eb0 ; G 2471
2328
+ U 7857 ; WX 675 ; N uni1eb1 ; G 2472
2329
+ U 7858 ; WX 774 ; N uni1eb2 ; G 2473
2330
+ U 7859 ; WX 675 ; N uni1eb3 ; G 2474
2331
+ U 7860 ; WX 774 ; N uni1eb4 ; G 2475
2332
+ U 7861 ; WX 675 ; N uni1eb5 ; G 2476
2333
+ U 7862 ; WX 774 ; N uni1eb6 ; G 2477
2334
+ U 7863 ; WX 675 ; N uni1eb7 ; G 2478
2335
+ U 7864 ; WX 683 ; N uni1eb8 ; G 2479
2336
+ U 7865 ; WX 678 ; N uni1eb9 ; G 2480
2337
+ U 7866 ; WX 683 ; N uni1eba ; G 2481
2338
+ U 7867 ; WX 678 ; N uni1ebb ; G 2482
2339
+ U 7868 ; WX 683 ; N uni1ebc ; G 2483
2340
+ U 7869 ; WX 678 ; N uni1ebd ; G 2484
2341
+ U 7870 ; WX 683 ; N uni1ebe ; G 2485
2342
+ U 7871 ; WX 678 ; N uni1ebf ; G 2486
2343
+ U 7872 ; WX 683 ; N uni1ec0 ; G 2487
2344
+ U 7873 ; WX 678 ; N uni1ec1 ; G 2488
2345
+ U 7874 ; WX 683 ; N uni1ec2 ; G 2489
2346
+ U 7875 ; WX 678 ; N uni1ec3 ; G 2490
2347
+ U 7876 ; WX 683 ; N uni1ec4 ; G 2491
2348
+ U 7877 ; WX 678 ; N uni1ec5 ; G 2492
2349
+ U 7878 ; WX 683 ; N uni1ec6 ; G 2493
2350
+ U 7879 ; WX 678 ; N uni1ec7 ; G 2494
2351
+ U 7880 ; WX 372 ; N uni1ec8 ; G 2495
2352
+ U 7881 ; WX 343 ; N uni1ec9 ; G 2496
2353
+ U 7882 ; WX 372 ; N uni1eca ; G 2497
2354
+ U 7883 ; WX 343 ; N uni1ecb ; G 2498
2355
+ U 7884 ; WX 850 ; N uni1ecc ; G 2499
2356
+ U 7885 ; WX 687 ; N uni1ecd ; G 2500
2357
+ U 7886 ; WX 850 ; N uni1ece ; G 2501
2358
+ U 7887 ; WX 687 ; N uni1ecf ; G 2502
2359
+ U 7888 ; WX 850 ; N uni1ed0 ; G 2503
2360
+ U 7889 ; WX 687 ; N uni1ed1 ; G 2504
2361
+ U 7890 ; WX 850 ; N uni1ed2 ; G 2505
2362
+ U 7891 ; WX 687 ; N uni1ed3 ; G 2506
2363
+ U 7892 ; WX 850 ; N uni1ed4 ; G 2507
2364
+ U 7893 ; WX 687 ; N uni1ed5 ; G 2508
2365
+ U 7894 ; WX 850 ; N uni1ed6 ; G 2509
2366
+ U 7895 ; WX 687 ; N uni1ed7 ; G 2510
2367
+ U 7896 ; WX 850 ; N uni1ed8 ; G 2511
2368
+ U 7897 ; WX 687 ; N uni1ed9 ; G 2512
2369
+ U 7898 ; WX 874 ; N uni1eda ; G 2513
2370
+ U 7899 ; WX 687 ; N uni1edb ; G 2514
2371
+ U 7900 ; WX 874 ; N uni1edc ; G 2515
2372
+ U 7901 ; WX 687 ; N uni1edd ; G 2516
2373
+ U 7902 ; WX 874 ; N uni1ede ; G 2517
2374
+ U 7903 ; WX 687 ; N uni1edf ; G 2518
2375
+ U 7904 ; WX 874 ; N uni1ee0 ; G 2519
2376
+ U 7905 ; WX 687 ; N uni1ee1 ; G 2520
2377
+ U 7906 ; WX 874 ; N uni1ee2 ; G 2521
2378
+ U 7907 ; WX 687 ; N uni1ee3 ; G 2522
2379
+ U 7908 ; WX 812 ; N uni1ee4 ; G 2523
2380
+ U 7909 ; WX 712 ; N uni1ee5 ; G 2524
2381
+ U 7910 ; WX 812 ; N uni1ee6 ; G 2525
2382
+ U 7911 ; WX 712 ; N uni1ee7 ; G 2526
2383
+ U 7912 ; WX 835 ; N uni1ee8 ; G 2527
2384
+ U 7913 ; WX 712 ; N uni1ee9 ; G 2528
2385
+ U 7914 ; WX 835 ; N uni1eea ; G 2529
2386
+ U 7915 ; WX 712 ; N uni1eeb ; G 2530
2387
+ U 7916 ; WX 835 ; N uni1eec ; G 2531
2388
+ U 7917 ; WX 712 ; N uni1eed ; G 2532
2389
+ U 7918 ; WX 835 ; N uni1eee ; G 2533
2390
+ U 7919 ; WX 712 ; N uni1eef ; G 2534
2391
+ U 7920 ; WX 835 ; N uni1ef0 ; G 2535
2392
+ U 7921 ; WX 712 ; N uni1ef1 ; G 2536
2393
+ U 7922 ; WX 724 ; N uni1ef2 ; G 2537
2394
+ U 7923 ; WX 652 ; N uni1ef3 ; G 2538
2395
+ U 7924 ; WX 724 ; N uni1ef4 ; G 2539
2396
+ U 7925 ; WX 652 ; N uni1ef5 ; G 2540
2397
+ U 7926 ; WX 724 ; N uni1ef6 ; G 2541
2398
+ U 7927 ; WX 652 ; N uni1ef7 ; G 2542
2399
+ U 7928 ; WX 724 ; N uni1ef8 ; G 2543
2400
+ U 7929 ; WX 652 ; N uni1ef9 ; G 2544
2401
+ U 7930 ; WX 953 ; N uni1efa ; G 2545
2402
+ U 7931 ; WX 644 ; N uni1efb ; G 2546
2403
+ U 7936 ; WX 687 ; N uni1f00 ; G 2547
2404
+ U 7937 ; WX 687 ; N uni1f01 ; G 2548
2405
+ U 7938 ; WX 687 ; N uni1f02 ; G 2549
2406
+ U 7939 ; WX 687 ; N uni1f03 ; G 2550
2407
+ U 7940 ; WX 687 ; N uni1f04 ; G 2551
2408
+ U 7941 ; WX 687 ; N uni1f05 ; G 2552
2409
+ U 7942 ; WX 687 ; N uni1f06 ; G 2553
2410
+ U 7943 ; WX 687 ; N uni1f07 ; G 2554
2411
+ U 7944 ; WX 774 ; N uni1f08 ; G 2555
2412
+ U 7945 ; WX 774 ; N uni1f09 ; G 2556
2413
+ U 7946 ; WX 1041 ; N uni1f0a ; G 2557
2414
+ U 7947 ; WX 1043 ; N uni1f0b ; G 2558
2415
+ U 7948 ; WX 935 ; N uni1f0c ; G 2559
2416
+ U 7949 ; WX 963 ; N uni1f0d ; G 2560
2417
+ U 7950 ; WX 835 ; N uni1f0e ; G 2561
2418
+ U 7951 ; WX 859 ; N uni1f0f ; G 2562
2419
+ U 7952 ; WX 557 ; N uni1f10 ; G 2563
2420
+ U 7953 ; WX 557 ; N uni1f11 ; G 2564
2421
+ U 7954 ; WX 557 ; N uni1f12 ; G 2565
2422
+ U 7955 ; WX 557 ; N uni1f13 ; G 2566
2423
+ U 7956 ; WX 557 ; N uni1f14 ; G 2567
2424
+ U 7957 ; WX 557 ; N uni1f15 ; G 2568
2425
+ U 7960 ; WX 792 ; N uni1f18 ; G 2569
2426
+ U 7961 ; WX 794 ; N uni1f19 ; G 2570
2427
+ U 7962 ; WX 1100 ; N uni1f1a ; G 2571
2428
+ U 7963 ; WX 1096 ; N uni1f1b ; G 2572
2429
+ U 7964 ; WX 1023 ; N uni1f1c ; G 2573
2430
+ U 7965 ; WX 1052 ; N uni1f1d ; G 2574
2431
+ U 7968 ; WX 712 ; N uni1f20 ; G 2575
2432
+ U 7969 ; WX 712 ; N uni1f21 ; G 2576
2433
+ U 7970 ; WX 712 ; N uni1f22 ; G 2577
2434
+ U 7971 ; WX 712 ; N uni1f23 ; G 2578
2435
+ U 7972 ; WX 712 ; N uni1f24 ; G 2579
2436
+ U 7973 ; WX 712 ; N uni1f25 ; G 2580
2437
+ U 7974 ; WX 712 ; N uni1f26 ; G 2581
2438
+ U 7975 ; WX 712 ; N uni1f27 ; G 2582
2439
+ U 7976 ; WX 945 ; N uni1f28 ; G 2583
2440
+ U 7977 ; WX 951 ; N uni1f29 ; G 2584
2441
+ U 7978 ; WX 1250 ; N uni1f2a ; G 2585
2442
+ U 7979 ; WX 1250 ; N uni1f2b ; G 2586
2443
+ U 7980 ; WX 1180 ; N uni1f2c ; G 2587
2444
+ U 7981 ; WX 1206 ; N uni1f2d ; G 2588
2445
+ U 7982 ; WX 1054 ; N uni1f2e ; G 2589
2446
+ U 7983 ; WX 1063 ; N uni1f2f ; G 2590
2447
+ U 7984 ; WX 390 ; N uni1f30 ; G 2591
2448
+ U 7985 ; WX 390 ; N uni1f31 ; G 2592
2449
+ U 7986 ; WX 390 ; N uni1f32 ; G 2593
2450
+ U 7987 ; WX 390 ; N uni1f33 ; G 2594
2451
+ U 7988 ; WX 390 ; N uni1f34 ; G 2595
2452
+ U 7989 ; WX 390 ; N uni1f35 ; G 2596
2453
+ U 7990 ; WX 390 ; N uni1f36 ; G 2597
2454
+ U 7991 ; WX 390 ; N uni1f37 ; G 2598
2455
+ U 7992 ; WX 483 ; N uni1f38 ; G 2599
2456
+ U 7993 ; WX 489 ; N uni1f39 ; G 2600
2457
+ U 7994 ; WX 777 ; N uni1f3a ; G 2601
2458
+ U 7995 ; WX 785 ; N uni1f3b ; G 2602
2459
+ U 7996 ; WX 712 ; N uni1f3c ; G 2603
2460
+ U 7997 ; WX 738 ; N uni1f3d ; G 2604
2461
+ U 7998 ; WX 604 ; N uni1f3e ; G 2605
2462
+ U 7999 ; WX 604 ; N uni1f3f ; G 2606
2463
+ U 8000 ; WX 687 ; N uni1f40 ; G 2607
2464
+ U 8001 ; WX 687 ; N uni1f41 ; G 2608
2465
+ U 8002 ; WX 687 ; N uni1f42 ; G 2609
2466
+ U 8003 ; WX 687 ; N uni1f43 ; G 2610
2467
+ U 8004 ; WX 687 ; N uni1f44 ; G 2611
2468
+ U 8005 ; WX 687 ; N uni1f45 ; G 2612
2469
+ U 8008 ; WX 892 ; N uni1f48 ; G 2613
2470
+ U 8009 ; WX 933 ; N uni1f49 ; G 2614
2471
+ U 8010 ; WX 1221 ; N uni1f4a ; G 2615
2472
+ U 8011 ; WX 1224 ; N uni1f4b ; G 2616
2473
+ U 8012 ; WX 1053 ; N uni1f4c ; G 2617
2474
+ U 8013 ; WX 1082 ; N uni1f4d ; G 2618
2475
+ U 8016 ; WX 675 ; N uni1f50 ; G 2619
2476
+ U 8017 ; WX 675 ; N uni1f51 ; G 2620
2477
+ U 8018 ; WX 675 ; N uni1f52 ; G 2621
2478
+ U 8019 ; WX 675 ; N uni1f53 ; G 2622
2479
+ U 8020 ; WX 675 ; N uni1f54 ; G 2623
2480
+ U 8021 ; WX 675 ; N uni1f55 ; G 2624
2481
+ U 8022 ; WX 675 ; N uni1f56 ; G 2625
2482
+ U 8023 ; WX 675 ; N uni1f57 ; G 2626
2483
+ U 8025 ; WX 930 ; N uni1f59 ; G 2627
2484
+ U 8027 ; WX 1184 ; N uni1f5b ; G 2628
2485
+ U 8029 ; WX 1199 ; N uni1f5d ; G 2629
2486
+ U 8031 ; WX 1049 ; N uni1f5f ; G 2630
2487
+ U 8032 ; WX 869 ; N uni1f60 ; G 2631
2488
+ U 8033 ; WX 869 ; N uni1f61 ; G 2632
2489
+ U 8034 ; WX 869 ; N uni1f62 ; G 2633
2490
+ U 8035 ; WX 869 ; N uni1f63 ; G 2634
2491
+ U 8036 ; WX 869 ; N uni1f64 ; G 2635
2492
+ U 8037 ; WX 869 ; N uni1f65 ; G 2636
2493
+ U 8038 ; WX 869 ; N uni1f66 ; G 2637
2494
+ U 8039 ; WX 869 ; N uni1f67 ; G 2638
2495
+ U 8040 ; WX 909 ; N uni1f68 ; G 2639
2496
+ U 8041 ; WX 958 ; N uni1f69 ; G 2640
2497
+ U 8042 ; WX 1246 ; N uni1f6a ; G 2641
2498
+ U 8043 ; WX 1251 ; N uni1f6b ; G 2642
2499
+ U 8044 ; WX 1076 ; N uni1f6c ; G 2643
2500
+ U 8045 ; WX 1105 ; N uni1f6d ; G 2644
2501
+ U 8046 ; WX 1028 ; N uni1f6e ; G 2645
2502
+ U 8047 ; WX 1076 ; N uni1f6f ; G 2646
2503
+ U 8048 ; WX 687 ; N uni1f70 ; G 2647
2504
+ U 8049 ; WX 687 ; N uni1f71 ; G 2648
2505
+ U 8050 ; WX 557 ; N uni1f72 ; G 2649
2506
+ U 8051 ; WX 557 ; N uni1f73 ; G 2650
2507
+ U 8052 ; WX 712 ; N uni1f74 ; G 2651
2508
+ U 8053 ; WX 712 ; N uni1f75 ; G 2652
2509
+ U 8054 ; WX 390 ; N uni1f76 ; G 2653
2510
+ U 8055 ; WX 390 ; N uni1f77 ; G 2654
2511
+ U 8056 ; WX 687 ; N uni1f78 ; G 2655
2512
+ U 8057 ; WX 687 ; N uni1f79 ; G 2656
2513
+ U 8058 ; WX 675 ; N uni1f7a ; G 2657
2514
+ U 8059 ; WX 675 ; N uni1f7b ; G 2658
2515
+ U 8060 ; WX 869 ; N uni1f7c ; G 2659
2516
+ U 8061 ; WX 869 ; N uni1f7d ; G 2660
2517
+ U 8064 ; WX 687 ; N uni1f80 ; G 2661
2518
+ U 8065 ; WX 687 ; N uni1f81 ; G 2662
2519
+ U 8066 ; WX 687 ; N uni1f82 ; G 2663
2520
+ U 8067 ; WX 687 ; N uni1f83 ; G 2664
2521
+ U 8068 ; WX 687 ; N uni1f84 ; G 2665
2522
+ U 8069 ; WX 687 ; N uni1f85 ; G 2666
2523
+ U 8070 ; WX 687 ; N uni1f86 ; G 2667
2524
+ U 8071 ; WX 687 ; N uni1f87 ; G 2668
2525
+ U 8072 ; WX 774 ; N uni1f88 ; G 2669
2526
+ U 8073 ; WX 774 ; N uni1f89 ; G 2670
2527
+ U 8074 ; WX 1041 ; N uni1f8a ; G 2671
2528
+ U 8075 ; WX 1043 ; N uni1f8b ; G 2672
2529
+ U 8076 ; WX 935 ; N uni1f8c ; G 2673
2530
+ U 8077 ; WX 963 ; N uni1f8d ; G 2674
2531
+ U 8078 ; WX 835 ; N uni1f8e ; G 2675
2532
+ U 8079 ; WX 859 ; N uni1f8f ; G 2676
2533
+ U 8080 ; WX 712 ; N uni1f90 ; G 2677
2534
+ U 8081 ; WX 712 ; N uni1f91 ; G 2678
2535
+ U 8082 ; WX 712 ; N uni1f92 ; G 2679
2536
+ U 8083 ; WX 712 ; N uni1f93 ; G 2680
2537
+ U 8084 ; WX 712 ; N uni1f94 ; G 2681
2538
+ U 8085 ; WX 712 ; N uni1f95 ; G 2682
2539
+ U 8086 ; WX 712 ; N uni1f96 ; G 2683
2540
+ U 8087 ; WX 712 ; N uni1f97 ; G 2684
2541
+ U 8088 ; WX 945 ; N uni1f98 ; G 2685
2542
+ U 8089 ; WX 951 ; N uni1f99 ; G 2686
2543
+ U 8090 ; WX 1250 ; N uni1f9a ; G 2687
2544
+ U 8091 ; WX 1250 ; N uni1f9b ; G 2688
2545
+ U 8092 ; WX 1180 ; N uni1f9c ; G 2689
2546
+ U 8093 ; WX 1206 ; N uni1f9d ; G 2690
2547
+ U 8094 ; WX 1054 ; N uni1f9e ; G 2691
2548
+ U 8095 ; WX 1063 ; N uni1f9f ; G 2692
2549
+ U 8096 ; WX 869 ; N uni1fa0 ; G 2693
2550
+ U 8097 ; WX 869 ; N uni1fa1 ; G 2694
2551
+ U 8098 ; WX 869 ; N uni1fa2 ; G 2695
2552
+ U 8099 ; WX 869 ; N uni1fa3 ; G 2696
2553
+ U 8100 ; WX 869 ; N uni1fa4 ; G 2697
2554
+ U 8101 ; WX 869 ; N uni1fa5 ; G 2698
2555
+ U 8102 ; WX 869 ; N uni1fa6 ; G 2699
2556
+ U 8103 ; WX 869 ; N uni1fa7 ; G 2700
2557
+ U 8104 ; WX 909 ; N uni1fa8 ; G 2701
2558
+ U 8105 ; WX 958 ; N uni1fa9 ; G 2702
2559
+ U 8106 ; WX 1246 ; N uni1faa ; G 2703
2560
+ U 8107 ; WX 1251 ; N uni1fab ; G 2704
2561
+ U 8108 ; WX 1076 ; N uni1fac ; G 2705
2562
+ U 8109 ; WX 1105 ; N uni1fad ; G 2706
2563
+ U 8110 ; WX 1028 ; N uni1fae ; G 2707
2564
+ U 8111 ; WX 1076 ; N uni1faf ; G 2708
2565
+ U 8112 ; WX 687 ; N uni1fb0 ; G 2709
2566
+ U 8113 ; WX 687 ; N uni1fb1 ; G 2710
2567
+ U 8114 ; WX 687 ; N uni1fb2 ; G 2711
2568
+ U 8115 ; WX 687 ; N uni1fb3 ; G 2712
2569
+ U 8116 ; WX 687 ; N uni1fb4 ; G 2713
2570
+ U 8118 ; WX 687 ; N uni1fb6 ; G 2714
2571
+ U 8119 ; WX 687 ; N uni1fb7 ; G 2715
2572
+ U 8120 ; WX 774 ; N uni1fb8 ; G 2716
2573
+ U 8121 ; WX 774 ; N uni1fb9 ; G 2717
2574
+ U 8122 ; WX 876 ; N uni1fba ; G 2718
2575
+ U 8123 ; WX 797 ; N uni1fbb ; G 2719
2576
+ U 8124 ; WX 774 ; N uni1fbc ; G 2720
2577
+ U 8125 ; WX 500 ; N uni1fbd ; G 2721
2578
+ U 8126 ; WX 500 ; N uni1fbe ; G 2722
2579
+ U 8127 ; WX 500 ; N uni1fbf ; G 2723
2580
+ U 8128 ; WX 500 ; N uni1fc0 ; G 2724
2581
+ U 8129 ; WX 500 ; N uni1fc1 ; G 2725
2582
+ U 8130 ; WX 712 ; N uni1fc2 ; G 2726
2583
+ U 8131 ; WX 712 ; N uni1fc3 ; G 2727
2584
+ U 8132 ; WX 712 ; N uni1fc4 ; G 2728
2585
+ U 8134 ; WX 712 ; N uni1fc6 ; G 2729
2586
+ U 8135 ; WX 712 ; N uni1fc7 ; G 2730
2587
+ U 8136 ; WX 929 ; N uni1fc8 ; G 2731
2588
+ U 8137 ; WX 846 ; N uni1fc9 ; G 2732
2589
+ U 8138 ; WX 1080 ; N uni1fca ; G 2733
2590
+ U 8139 ; WX 1009 ; N uni1fcb ; G 2734
2591
+ U 8140 ; WX 837 ; N uni1fcc ; G 2735
2592
+ U 8141 ; WX 500 ; N uni1fcd ; G 2736
2593
+ U