prawn-git 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/COPYING +2 -0
  4. data/GPLv2 +340 -0
  5. data/GPLv3 +674 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +56 -0
  8. data/Rakefile +55 -0
  9. data/data/fonts/Courier-Bold.afm +342 -0
  10. data/data/fonts/Courier-BoldOblique.afm +342 -0
  11. data/data/fonts/Courier-Oblique.afm +342 -0
  12. data/data/fonts/Courier.afm +342 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/images/16bit.alpha +0 -0
  25. data/data/images/16bit.color +0 -0
  26. data/data/images/16bit.png +0 -0
  27. data/data/images/arrow.png +0 -0
  28. data/data/images/arrow2.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.color +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/dice_interlaced.png +0 -0
  33. data/data/images/fractal.jpg +0 -0
  34. data/data/images/indexed_color.dat +0 -0
  35. data/data/images/indexed_color.png +0 -0
  36. data/data/images/letterhead.jpg +0 -0
  37. data/data/images/license.md +8 -0
  38. data/data/images/page_white_text.alpha +0 -0
  39. data/data/images/page_white_text.color +0 -0
  40. data/data/images/page_white_text.png +0 -0
  41. data/data/images/pal_bk.png +0 -0
  42. data/data/images/pigs.jpg +0 -0
  43. data/data/images/prawn.png +0 -0
  44. data/data/images/ruport.png +0 -0
  45. data/data/images/ruport_data.dat +0 -0
  46. data/data/images/ruport_transparent.png +0 -0
  47. data/data/images/ruport_type0.png +0 -0
  48. data/data/images/stef.jpg +0 -0
  49. data/data/images/tru256.bmp +0 -0
  50. data/data/images/web-links.dat +1 -0
  51. data/data/images/web-links.png +0 -0
  52. data/data/pdfs/complex_template.pdf +0 -0
  53. data/data/pdfs/contains_ttf_font.pdf +0 -0
  54. data/data/pdfs/encrypted.pdf +0 -0
  55. data/data/pdfs/form.pdf +820 -0
  56. data/data/pdfs/hexagon.pdf +61 -0
  57. data/data/pdfs/indirect_reference.pdf +86 -0
  58. data/data/pdfs/multipage_template.pdf +127 -0
  59. data/data/pdfs/nested_pages.pdf +118 -0
  60. data/data/pdfs/page_without_mediabox.pdf +193 -0
  61. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  62. data/data/pdfs/two_hexagons.pdf +90 -0
  63. data/data/pdfs/version_1_6.pdf +61 -0
  64. data/data/shift_jis_text.txt +1 -0
  65. data/lib/prawn.rb +89 -0
  66. data/lib/prawn/document.rb +706 -0
  67. data/lib/prawn/document/bounding_box.rb +539 -0
  68. data/lib/prawn/document/column_box.rb +144 -0
  69. data/lib/prawn/document/internals.rb +58 -0
  70. data/lib/prawn/document/span.rb +57 -0
  71. data/lib/prawn/encoding.rb +87 -0
  72. data/lib/prawn/errors.rb +80 -0
  73. data/lib/prawn/font.rb +413 -0
  74. data/lib/prawn/font/afm.rb +256 -0
  75. data/lib/prawn/font/dfont.rb +43 -0
  76. data/lib/prawn/font/ttf.rb +355 -0
  77. data/lib/prawn/font_metric_cache.rb +46 -0
  78. data/lib/prawn/graphics.rb +646 -0
  79. data/lib/prawn/graphics/cap_style.rb +47 -0
  80. data/lib/prawn/graphics/color.rb +232 -0
  81. data/lib/prawn/graphics/dash.rb +109 -0
  82. data/lib/prawn/graphics/join_style.rb +49 -0
  83. data/lib/prawn/graphics/patterns.rb +126 -0
  84. data/lib/prawn/graphics/transformation.rb +157 -0
  85. data/lib/prawn/graphics/transparency.rb +101 -0
  86. data/lib/prawn/grid.rb +279 -0
  87. data/lib/prawn/image_handler.rb +44 -0
  88. data/lib/prawn/images.rb +199 -0
  89. data/lib/prawn/images/image.rb +49 -0
  90. data/lib/prawn/images/jpg.rb +91 -0
  91. data/lib/prawn/images/png.rb +290 -0
  92. data/lib/prawn/measurement_extensions.rb +50 -0
  93. data/lib/prawn/measurements.rb +77 -0
  94. data/lib/prawn/outline.rb +289 -0
  95. data/lib/prawn/repeater.rb +124 -0
  96. data/lib/prawn/security.rb +288 -0
  97. data/lib/prawn/security/arcfour.rb +54 -0
  98. data/lib/prawn/soft_mask.rb +94 -0
  99. data/lib/prawn/stamp.rb +136 -0
  100. data/lib/prawn/text.rb +437 -0
  101. data/lib/prawn/text/box.rb +141 -0
  102. data/lib/prawn/text/formatted.rb +7 -0
  103. data/lib/prawn/text/formatted/arranger.rb +290 -0
  104. data/lib/prawn/text/formatted/box.rb +614 -0
  105. data/lib/prawn/text/formatted/fragment.rb +264 -0
  106. data/lib/prawn/text/formatted/line_wrap.rb +277 -0
  107. data/lib/prawn/text/formatted/parser.rb +224 -0
  108. data/lib/prawn/text/formatted/wrap.rb +160 -0
  109. data/lib/prawn/utilities.rb +46 -0
  110. data/lib/prawn/version.rb +5 -0
  111. data/lib/prawn/view.rb +91 -0
  112. data/manual/absolute_position.pdf +0 -0
  113. data/manual/basic_concepts/adding_pages.rb +27 -0
  114. data/manual/basic_concepts/basic_concepts.rb +36 -0
  115. data/manual/basic_concepts/creation.rb +39 -0
  116. data/manual/basic_concepts/cursor.rb +33 -0
  117. data/manual/basic_concepts/measurement.rb +25 -0
  118. data/manual/basic_concepts/origin.rb +38 -0
  119. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  120. data/manual/basic_concepts/view.rb +42 -0
  121. data/manual/bounding_box/bounding_box.rb +39 -0
  122. data/manual/bounding_box/bounds.rb +49 -0
  123. data/manual/bounding_box/canvas.rb +24 -0
  124. data/manual/bounding_box/creation.rb +23 -0
  125. data/manual/bounding_box/indentation.rb +46 -0
  126. data/manual/bounding_box/nesting.rb +45 -0
  127. data/manual/bounding_box/russian_boxes.rb +40 -0
  128. data/manual/bounding_box/stretchy.rb +31 -0
  129. data/manual/contents.rb +29 -0
  130. data/manual/cover.rb +39 -0
  131. data/manual/document_and_page_options/background.rb +27 -0
  132. data/manual/document_and_page_options/document_and_page_options.rb +32 -0
  133. data/manual/document_and_page_options/metadata.rb +23 -0
  134. data/manual/document_and_page_options/page_margins.rb +38 -0
  135. data/manual/document_and_page_options/page_size.rb +34 -0
  136. data/manual/document_and_page_options/print_scaling.rb +20 -0
  137. data/manual/example_helper.rb +7 -0
  138. data/manual/graphics/circle_and_ellipse.rb +22 -0
  139. data/manual/graphics/color.rb +24 -0
  140. data/manual/graphics/common_lines.rb +30 -0
  141. data/manual/graphics/fill_and_stroke.rb +42 -0
  142. data/manual/graphics/fill_rules.rb +37 -0
  143. data/manual/graphics/gradients.rb +37 -0
  144. data/manual/graphics/graphics.rb +58 -0
  145. data/manual/graphics/helper.rb +24 -0
  146. data/manual/graphics/line_width.rb +35 -0
  147. data/manual/graphics/lines_and_curves.rb +41 -0
  148. data/manual/graphics/polygon.rb +29 -0
  149. data/manual/graphics/rectangle.rb +21 -0
  150. data/manual/graphics/rotate.rb +28 -0
  151. data/manual/graphics/scale.rb +41 -0
  152. data/manual/graphics/soft_masks.rb +46 -0
  153. data/manual/graphics/stroke_cap.rb +31 -0
  154. data/manual/graphics/stroke_dash.rb +48 -0
  155. data/manual/graphics/stroke_join.rb +30 -0
  156. data/manual/graphics/translate.rb +29 -0
  157. data/manual/graphics/transparency.rb +35 -0
  158. data/manual/how_to_read_this_manual.rb +40 -0
  159. data/manual/images/absolute_position.rb +23 -0
  160. data/manual/images/fit.rb +21 -0
  161. data/manual/images/horizontal.rb +25 -0
  162. data/manual/images/images.rb +40 -0
  163. data/manual/images/plain_image.rb +18 -0
  164. data/manual/images/scale.rb +22 -0
  165. data/manual/images/vertical.rb +28 -0
  166. data/manual/images/width_and_height.rb +25 -0
  167. data/manual/layout/boxes.rb +27 -0
  168. data/manual/layout/content.rb +25 -0
  169. data/manual/layout/layout.rb +28 -0
  170. data/manual/layout/simple_grid.rb +23 -0
  171. data/manual/outline/add_subsection_to.rb +61 -0
  172. data/manual/outline/insert_section_after.rb +47 -0
  173. data/manual/outline/outline.rb +32 -0
  174. data/manual/outline/sections_and_pages.rb +67 -0
  175. data/manual/repeatable_content/alternate_page_numbering.rb +32 -0
  176. data/manual/repeatable_content/page_numbering.rb +54 -0
  177. data/manual/repeatable_content/repeatable_content.rb +32 -0
  178. data/manual/repeatable_content/repeater.rb +55 -0
  179. data/manual/repeatable_content/stamp.rb +41 -0
  180. data/manual/security/encryption.rb +31 -0
  181. data/manual/security/permissions.rb +38 -0
  182. data/manual/security/security.rb +28 -0
  183. data/manual/table.rb +16 -0
  184. data/manual/text/alignment.rb +44 -0
  185. data/manual/text/color.rb +24 -0
  186. data/manual/text/column_box.rb +32 -0
  187. data/manual/text/fallback_fonts.rb +37 -0
  188. data/manual/text/font.rb +41 -0
  189. data/manual/text/font_size.rb +45 -0
  190. data/manual/text/font_style.rb +23 -0
  191. data/manual/text/formatted_callbacks.rb +60 -0
  192. data/manual/text/formatted_text.rb +50 -0
  193. data/manual/text/free_flowing_text.rb +51 -0
  194. data/manual/text/inline.rb +41 -0
  195. data/manual/text/kerning_and_character_spacing.rb +39 -0
  196. data/manual/text/leading.rb +25 -0
  197. data/manual/text/line_wrapping.rb +41 -0
  198. data/manual/text/paragraph_indentation.rb +34 -0
  199. data/manual/text/positioned_text.rb +38 -0
  200. data/manual/text/registering_families.rb +48 -0
  201. data/manual/text/rendering_and_color.rb +37 -0
  202. data/manual/text/right_to_left_text.rb +47 -0
  203. data/manual/text/rotation.rb +43 -0
  204. data/manual/text/single_usage.rb +37 -0
  205. data/manual/text/text.rb +73 -0
  206. data/manual/text/text_box_excess.rb +32 -0
  207. data/manual/text/text_box_extensions.rb +45 -0
  208. data/manual/text/text_box_overflow.rb +48 -0
  209. data/manual/text/utf8.rb +28 -0
  210. data/manual/text/win_ansi_charset.rb +60 -0
  211. data/prawn.gemspec +45 -0
  212. data/spec/acceptance/png.rb +25 -0
  213. data/spec/annotations_spec.rb +74 -0
  214. data/spec/bounding_box_spec.rb +510 -0
  215. data/spec/column_box_spec.rb +65 -0
  216. data/spec/data/curves.pdf +66 -0
  217. data/spec/destinations_spec.rb +15 -0
  218. data/spec/document_spec.rb +748 -0
  219. data/spec/extensions/encoding_helpers.rb +11 -0
  220. data/spec/extensions/mocha.rb +46 -0
  221. data/spec/font_metric_cache_spec.rb +52 -0
  222. data/spec/font_spec.rb +474 -0
  223. data/spec/formatted_text_arranger_spec.rb +421 -0
  224. data/spec/formatted_text_box_spec.rb +705 -0
  225. data/spec/formatted_text_fragment_spec.rb +298 -0
  226. data/spec/graphics_spec.rb +683 -0
  227. data/spec/grid_spec.rb +96 -0
  228. data/spec/image_handler_spec.rb +54 -0
  229. data/spec/images_spec.rb +153 -0
  230. data/spec/inline_formatted_text_parser_spec.rb +564 -0
  231. data/spec/jpg_spec.rb +25 -0
  232. data/spec/line_wrap_spec.rb +367 -0
  233. data/spec/measurement_units_spec.rb +25 -0
  234. data/spec/outline_spec.rb +430 -0
  235. data/spec/png_spec.rb +245 -0
  236. data/spec/reference_spec.rb +25 -0
  237. data/spec/repeater_spec.rb +160 -0
  238. data/spec/security_spec.rb +158 -0
  239. data/spec/soft_mask_spec.rb +79 -0
  240. data/spec/span_spec.rb +44 -0
  241. data/spec/spec_helper.rb +54 -0
  242. data/spec/stamp_spec.rb +160 -0
  243. data/spec/stroke_styles_spec.rb +211 -0
  244. data/spec/text_at_spec.rb +143 -0
  245. data/spec/text_box_spec.rb +1043 -0
  246. data/spec/text_rendering_mode_spec.rb +45 -0
  247. data/spec/text_spacing_spec.rb +93 -0
  248. data/spec/text_spec.rb +557 -0
  249. data/spec/text_with_inline_formatting_spec.rb +35 -0
  250. data/spec/transparency_spec.rb +91 -0
  251. data/spec/view_spec.rb +43 -0
  252. metadata +509 -0
@@ -0,0 +1,539 @@
1
+ # encoding: utf-8
2
+
3
+ # bounding_box.rb : Implements a mechanism for shifting the coordinate space
4
+ #
5
+ # Copyright May 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Document
11
+ # @group Stable API
12
+
13
+ # :call-seq:
14
+ # bounding_box(point, options={}, &block)
15
+ #
16
+ # A bounding box serves two important purposes:
17
+ # * Provide bounds for flowing text, starting at a given point
18
+ # * Translate the origin (0,0) for graphics primitives
19
+ #
20
+ # A point and :width must be provided. :height is optional.
21
+ # (See stretchyness below)
22
+ #
23
+ # ==Positioning
24
+ #
25
+ # Bounding boxes are positioned relative to their top left corner and
26
+ # the width measurement is towards the right and height measurement is
27
+ # downwards.
28
+ #
29
+ # Usage:
30
+ #
31
+ # * Bounding box 100pt x 100pt in the absolute bottom left of the
32
+ # containing box:
33
+ #
34
+ # pdf.bounding_box([0,100], :width => 100, :height => 100)
35
+ # stroke_bounds
36
+ # end
37
+ #
38
+ # * Bounding box 200pt x 400pt high in the center of the page:
39
+ #
40
+ # x_pos = ((bounds.width / 2) - 150)
41
+ # y_pos = ((bounds.height / 2) + 200)
42
+ # pdf.bounding_box([x_pos, y_pos], :width => 300, :height => 400) do
43
+ # stroke_bounds
44
+ # end
45
+ #
46
+ # ==Flowing Text
47
+ #
48
+ # When flowing text, the usage of a bounding box is simple. Text will
49
+ # begin at the point specified, flowing the width of the bounding box.
50
+ # After the block exits, the cursor position will be moved to
51
+ # the bottom of the bounding box (y - height). If flowing text exceeds
52
+ # the height of the bounding box, the text will be continued on the next
53
+ # page, starting again at the top-left corner of the bounding box.
54
+ #
55
+ # Usage:
56
+ #
57
+ # pdf.bounding_box([100,500], :width => 100, :height => 300) do
58
+ # pdf.text "This text will flow in a very narrow box starting" +
59
+ # "from [100,500]. The pointer will then be moved to [100,200]" +
60
+ # "and return to the margin_box"
61
+ # end
62
+ #
63
+ # Note, this is a low level tool and is designed primarily for building
64
+ # other abstractions. If you just need to flow text on the page, you
65
+ # will want to look at span() and text_box() instead
66
+ #
67
+ # ==Translating Coordinates
68
+ #
69
+ # When translating coordinates, the idea is to allow the user to draw
70
+ # relative to the origin, and then translate their drawing to a specified
71
+ # area of the document, rather than adjust all their drawing coordinates
72
+ # to match this new region.
73
+ #
74
+ # Take for example two triangles which share one point, drawn from the
75
+ # origin:
76
+ #
77
+ # pdf.polygon [0,250], [0,0], [150,100]
78
+ # pdf.polygon [100,0], [150,100], [200,0]
79
+ #
80
+ # It would be easy enough to translate these triangles to another point,
81
+ # e.g [200,200]
82
+ #
83
+ # pdf.polygon [200,450], [200,200], [350,300]
84
+ # pdf.polygon [300,200], [350,300], [400,200]
85
+ #
86
+ # However, each time you want to move the drawing, you'd need to alter
87
+ # every point in the drawing calls, which as you might imagine, can become
88
+ # tedious.
89
+ #
90
+ # If instead, we think of the drawing as being bounded by a box, we can
91
+ # see that the image is 200 points wide by 250 points tall.
92
+ #
93
+ # To translate it to a new origin, we simply select a point at (x,y+height)
94
+ #
95
+ # Using the [200,200] example:
96
+ #
97
+ # pdf.bounding_box([200,450], :width => 200, :height => 250) do
98
+ # pdf.stroke do
99
+ # pdf.polygon [0,250], [0,0], [150,100]
100
+ # pdf.polygon [100,0], [150,100], [200,0]
101
+ # end
102
+ # end
103
+ #
104
+ # Notice that the drawing is still relative to the origin. If we want to
105
+ # move this drawing around the document, we simply need to recalculate the
106
+ # top-left corner of the rectangular bounding-box, and all of our graphics
107
+ # calls remain unmodified.
108
+ #
109
+ # ==Nesting Bounding Boxes
110
+ #
111
+ # At the top level, bounding boxes are specified relative to the document's
112
+ # margin_box (which is itself a bounding box). You can also nest bounding
113
+ # boxes, allowing you to build components which are relative to each other
114
+ #
115
+ # Usage:
116
+ #
117
+ # pdf.bounding_box([200,450], :width => 200, :height => 250) do
118
+ # pdf.stroke_bounds # Show the containing bounding box
119
+ # pdf.bounding_box([50,200], :width => 50, :height => 50) do
120
+ # # a 50x50 bounding box that starts 50 pixels left and 50 pixels down
121
+ # # the parent bounding box.
122
+ # pdf.stroke_bounds
123
+ # end
124
+ # end
125
+ #
126
+ # ==Stretchyness
127
+ #
128
+ # If you do not specify a height to a bounding box, it will become stretchy
129
+ # and its height will be calculated automatically as you stretch the box
130
+ # downwards.
131
+ #
132
+ # pdf.bounding_box([100,400], :width => 400) do
133
+ # pdf.text("The height of this box is #{pdf.bounds.height}")
134
+ # pdf.text('this is some text')
135
+ # pdf.text('this is some more text')
136
+ # pdf.text('and finally a bit more')
137
+ # pdf.text("Now the height of this box is #{pdf.bounds.height}")
138
+ # end
139
+ #
140
+ # ==Absolute Positioning
141
+ #
142
+ # If you wish to position the bounding boxes at absolute coordinates rather
143
+ # than relative to the margins or other bounding boxes, you can use canvas()
144
+ #
145
+ # pdf.bounding_box([50,500], :width => 200, :height => 300) do
146
+ # pdf.stroke_bounds
147
+ # pdf.canvas do
148
+ # Positioned outside the containing box at the 'real' (300,450)
149
+ # pdf.bounding_box([300,450], :width => 200, :height => 200) do
150
+ # pdf.stroke_bounds
151
+ # end
152
+ # end
153
+ # end
154
+ #
155
+ # Of course, if you use canvas, you will be responsible for ensuring that
156
+ # you remain within the printable area of your document.
157
+ #
158
+ def bounding_box(pt, *args, &block)
159
+ init_bounding_box(block) do |parent_box|
160
+ pt = map_to_absolute(pt)
161
+ @bounding_box = BoundingBox.new(self, parent_box, pt, *args)
162
+ end
163
+ end
164
+
165
+ # A shortcut to produce a bounding box which is mapped to the document's
166
+ # absolute coordinates, regardless of how things are nested or margin sizes.
167
+ #
168
+ # pdf.canvas do
169
+ # pdf.line pdf.bounds.bottom_left, pdf.bounds.top_right
170
+ # end
171
+ #
172
+ def canvas(&block)
173
+ init_bounding_box(block, :hold_position => true) do |_|
174
+ # Canvas bbox acts like margin_box in that its parent bounds are unset.
175
+ @bounding_box = BoundingBox.new(self, nil, [0,page.dimensions[3]],
176
+ :width => page.dimensions[2],
177
+ :height => page.dimensions[3]
178
+ )
179
+ end
180
+ end
181
+
182
+ private
183
+
184
+ def init_bounding_box(user_block, options={}, &init_block)
185
+ unless user_block
186
+ raise ArgumentError,
187
+ "bounding boxes require a block to be drawn within the box"
188
+ end
189
+
190
+ parent_box = @bounding_box
191
+
192
+ original_ypos = y
193
+
194
+ init_block.call(parent_box)
195
+
196
+ self.y = @bounding_box.absolute_top
197
+ user_block.call
198
+
199
+ # If the user actions did not modify the y position
200
+ # restore the original y position before the bounding
201
+ # box was created.
202
+
203
+ if y == @bounding_box.absolute_top
204
+ self.y = original_ypos
205
+ end
206
+
207
+ unless options[:hold_position] || @bounding_box.stretchy?
208
+ self.y = @bounding_box.absolute_bottom
209
+ end
210
+
211
+ created_box, @bounding_box = @bounding_box, parent_box
212
+
213
+ return created_box
214
+ end
215
+
216
+ # Low level layout helper that simplifies coordinate math.
217
+ #
218
+ # See Prawn::Document#bounding_box for a description of what this class
219
+ # is used for.
220
+ #
221
+ class BoundingBox
222
+
223
+ def initialize(document, parent, point, options={}) # @private
224
+ unless options[:width]
225
+ raise ArgumentError, "BoundingBox needs the :width option to be set"
226
+ end
227
+
228
+ @document = document
229
+ @parent = parent
230
+ @x, @y = point
231
+ @width, @height = options[:width], options[:height]
232
+ @total_left_padding = 0
233
+ @total_right_padding = 0
234
+ @stretched_height = nil
235
+ end
236
+
237
+ # @private
238
+
239
+ attr_reader :document, :parent
240
+
241
+ # @private
242
+ # The current indentation of the left side of the bounding box.
243
+ attr_reader :total_left_padding
244
+
245
+ # @private
246
+ # The current indentation of the right side of the bounding box.
247
+ attr_reader :total_right_padding
248
+
249
+ # The translated origin (x,y-height) which describes the location
250
+ # of the bottom left corner of the bounding box
251
+ #
252
+ # @private
253
+ def anchor
254
+ [@x, @y - height]
255
+ end
256
+
257
+ # Relative left x-coordinate of the bounding box. (Always 0)
258
+ #
259
+ # Example, position some text 3 pts from the left of the containing box:
260
+ #
261
+ # draw_text('hello', :at => [(bounds.left + 3), 0])
262
+ #
263
+ def left
264
+ 0
265
+ end
266
+
267
+
268
+ # Temporarily adjust the @x coordinate to allow for left_padding
269
+ #
270
+ # Example:
271
+ #
272
+ # indent 20 do
273
+ # text "20 points in"
274
+ # indent 30 do
275
+ # text "50 points in"
276
+ # end
277
+ # end
278
+ #
279
+ # indent 20, 20 do
280
+ # text "indented on both sides"
281
+ # end
282
+ #
283
+ # @private
284
+ def indent(left_padding, right_padding = 0, &block)
285
+ add_left_padding(left_padding)
286
+ add_right_padding(right_padding)
287
+ yield
288
+ ensure
289
+ @document.bounds.subtract_left_padding(left_padding)
290
+ @document.bounds.subtract_right_padding(right_padding)
291
+ end
292
+
293
+ # Increase the left padding of the bounding box.
294
+ # @private
295
+ def add_left_padding(left_padding)
296
+ @total_left_padding += left_padding
297
+ @x += left_padding
298
+ @width -= left_padding
299
+ end
300
+
301
+ # Decrease the left padding of the bounding box.
302
+ # @private
303
+ def subtract_left_padding(left_padding)
304
+ @total_left_padding -= left_padding
305
+ @x -= left_padding
306
+ @width += left_padding
307
+ end
308
+
309
+ # Increase the right padding of the bounding box.
310
+ # @private
311
+ def add_right_padding(right_padding)
312
+ @total_right_padding += right_padding
313
+ @width -= right_padding
314
+ end
315
+
316
+ # Decrease the right padding of the bounding box.
317
+ # @private
318
+ def subtract_right_padding(right_padding)
319
+ @total_right_padding -= right_padding
320
+ @width += right_padding
321
+ end
322
+
323
+ # Relative right x-coordinate of the bounding box. (Equal to the box width)
324
+ #
325
+ # Example, position some text 3 pts from the right of the containing box:
326
+ #
327
+ # draw_text('hello', :at => [(bounds.right - 3), 0])
328
+ #
329
+ def right
330
+ @width
331
+ end
332
+
333
+ # Relative top y-coordinate of the bounding box. (Equal to the box height)
334
+ #
335
+ # Example, position some text 3 pts from the top of the containing box:
336
+ #
337
+ # draw_text('hello', :at => [0, (bounds.top - 3)])
338
+ #
339
+ def top
340
+ height
341
+ end
342
+
343
+ # Relative bottom y-coordinate of the bounding box (Always 0)
344
+ #
345
+ # Example, position some text 3 pts from the bottom of the containing box:
346
+ #
347
+ # draw_text('hello', :at => [0, (bounds.bottom + 3)])
348
+ #
349
+ def bottom
350
+ 0
351
+ end
352
+
353
+ # Relative top-left point of the bounding_box
354
+ #
355
+ # Example, draw a line from the top left of the box diagonally to the
356
+ # bottom right:
357
+ #
358
+ # stroke do
359
+ # line(bounds.top_left, bounds.bottom_right)
360
+ # end
361
+ #
362
+ def top_left
363
+ [left,top]
364
+ end
365
+
366
+ # Relative top-right point of the bounding box
367
+ #
368
+ # Example, draw a line from the top_right of the box diagonally to the
369
+ # bottom left:
370
+ #
371
+ # stroke do
372
+ # line(bounds.top_right, bounds.bottom_left)
373
+ # end
374
+ #
375
+ def top_right
376
+ [right,top]
377
+ end
378
+
379
+ # Relative bottom-right point of the bounding box
380
+ #
381
+ # Example, draw a line along the right hand side of the page:
382
+ #
383
+ # stroke do
384
+ # line(bounds.bottom_right, bounds.top_right)
385
+ # end
386
+ #
387
+ def bottom_right
388
+ [right,bottom]
389
+ end
390
+
391
+ # Relative bottom-left point of the bounding box
392
+ #
393
+ # Example, draw a line along the left hand side of the page:
394
+ #
395
+ # stroke do
396
+ # line(bounds.bottom_left, bounds.top_left)
397
+ # end
398
+ #
399
+ def bottom_left
400
+ [left,bottom]
401
+ end
402
+
403
+ # Absolute left x-coordinate of the bounding box
404
+ #
405
+ def absolute_left
406
+ @x
407
+ end
408
+
409
+ # Absolute right x-coordinate of the bounding box
410
+ #
411
+ def absolute_right
412
+ @x + width
413
+ end
414
+
415
+ # Absolute top y-coordinate of the bounding box
416
+ #
417
+ def absolute_top
418
+ @y
419
+ end
420
+
421
+ # Absolute bottom y-coordinate of the bottom box
422
+ #
423
+ def absolute_bottom
424
+ @y - height
425
+ end
426
+
427
+ # Absolute top-left point of the bounding box
428
+ #
429
+ def absolute_top_left
430
+ [absolute_left, absolute_top]
431
+ end
432
+
433
+ # Absolute top-right point of the bounding box
434
+ #
435
+ def absolute_top_right
436
+ [absolute_right, absolute_top]
437
+ end
438
+
439
+ # Absolute bottom-left point of the bounding box
440
+ #
441
+ def absolute_bottom_left
442
+ [absolute_left, absolute_bottom]
443
+ end
444
+
445
+ # Absolute bottom-left point of the bounding box
446
+ #
447
+ def absolute_bottom_right
448
+ [absolute_right, absolute_bottom]
449
+ end
450
+
451
+ # Width of the bounding box
452
+ #
453
+ def width
454
+ @width
455
+ end
456
+
457
+ # Height of the bounding box. If the box is 'stretchy' (unspecified
458
+ # height attribute), height is calculated as the distance from the top of
459
+ # the box to the current drawing position.
460
+ #
461
+ def height
462
+ return @height if @height
463
+ @stretched_height = [(absolute_top - @document.y),
464
+ @stretched_height.to_f].max
465
+ end
466
+
467
+ # an alias for absolute_left
468
+ # @private
469
+ def left_side
470
+ absolute_left
471
+ end
472
+
473
+ # an alias for absolute_right
474
+ # @private
475
+ def right_side
476
+ absolute_right
477
+ end
478
+
479
+ # @group Extension API
480
+
481
+ # Moves to the top of the next page of the document, starting a new page
482
+ # if necessary.
483
+ #
484
+ def move_past_bottom
485
+ if @document.page_number == @document.page_count
486
+ @document.start_new_page
487
+ else
488
+ @document.go_to_page(@document.page_number + 1)
489
+ end
490
+ end
491
+
492
+ # Returns +false+ when the box has a defined height, +true+ when the height
493
+ # is being calculated on the fly based on the current vertical position.
494
+ #
495
+ def stretchy?
496
+ !@height
497
+ end
498
+
499
+ # Returns the innermost non-stretchy bounding box.
500
+ #
501
+ def reference_bounds
502
+ if stretchy?
503
+ raise "Can't find reference bounds: my parent is unset" unless @parent
504
+ @parent.reference_bounds
505
+ else
506
+ self
507
+ end
508
+ end
509
+
510
+ alias_method :update_height, :height
511
+
512
+ # Returns a deep copy of these bounds (including all parent bounds but
513
+ # not copying the reference to the Document).
514
+ #
515
+ # @private
516
+ def deep_copy
517
+ copy = dup
518
+ # Deep-copy the parent bounds
519
+ copy.instance_variable_set("@parent", if BoundingBox === @parent
520
+ @parent.deep_copy
521
+ end)
522
+ copy.instance_variable_set("@document", nil)
523
+ copy
524
+ end
525
+
526
+ # Restores a copy of the bounds taken by BoundingBox.deep_copy in the
527
+ # context of the given +document+. Does *not* set the bounds of the
528
+ # document to the resulting BoundingBox, only returns it.
529
+ #
530
+ # @private
531
+ def self.restore_deep_copy(bounds, document)
532
+ bounds.instance_variable_set("@document", document)
533
+ bounds
534
+ end
535
+
536
+ end
537
+
538
+ end
539
+ end