prawn 0.11.1 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +10 -0
- data/COPYING +2 -2
- data/GPLv2 +340 -0
- data/GPLv3 +674 -0
- data/Gemfile +11 -0
- data/LICENSE +1 -1
- data/Rakefile +29 -38
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.color +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.color +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.color +0 -0
- data/data/pdfs/nested_pages.pdf +13 -13
- data/lib/prawn/document/bounding_box.rb +87 -12
- data/lib/prawn/document/column_box.rb +57 -28
- data/lib/prawn/document/graphics_state.rb +11 -74
- data/lib/prawn/document/internals.rb +25 -23
- data/lib/prawn/document/snapshot.rb +11 -8
- data/lib/prawn/document/span.rb +12 -10
- data/lib/prawn/document.rb +250 -194
- data/lib/prawn/encoding.rb +9 -10
- data/lib/prawn/errors.rb +18 -29
- data/lib/prawn/font/afm.rb +52 -41
- data/lib/prawn/font/dfont.rb +4 -3
- data/lib/prawn/font/ttf.rb +44 -48
- data/lib/prawn/font.rb +138 -88
- data/lib/prawn/font_metric_cache.rb +47 -0
- data/lib/prawn/graphics/cap_style.rb +4 -3
- data/lib/prawn/graphics/color.rb +13 -5
- data/lib/prawn/graphics/dash.rb +53 -31
- data/lib/prawn/graphics/join_style.rb +9 -7
- data/lib/prawn/graphics/patterns.rb +138 -0
- data/lib/prawn/graphics/transformation.rb +10 -9
- data/lib/prawn/graphics/transparency.rb +3 -1
- data/lib/prawn/graphics.rb +316 -61
- data/lib/prawn/image_handler.rb +36 -0
- data/lib/prawn/images/image.rb +49 -0
- data/lib/prawn/images/jpg.rb +21 -15
- data/lib/prawn/images/png.rb +62 -119
- data/lib/prawn/images.rb +89 -108
- data/lib/prawn/layout/grid.rb +66 -54
- data/lib/prawn/layout.rb +10 -15
- data/lib/prawn/measurement_extensions.rb +10 -6
- data/lib/prawn/measurements.rb +27 -21
- data/lib/prawn/outline.rb +6 -308
- data/lib/prawn/repeater.rb +11 -9
- data/lib/prawn/security/arcfour.rb +1 -0
- data/lib/prawn/security.rb +55 -33
- data/lib/prawn/soft_mask.rb +96 -0
- data/lib/prawn/stamp.rb +5 -3
- data/lib/prawn/table/cell/image.rb +69 -0
- data/lib/prawn/table/cell/in_table.rb +4 -2
- data/lib/prawn/table/cell/span_dummy.rb +93 -0
- data/lib/prawn/table/cell/subtable.rb +2 -2
- data/lib/prawn/table/cell/text.rb +44 -26
- data/lib/prawn/table/cell.rb +302 -50
- data/lib/prawn/table/cells.rb +147 -49
- data/lib/prawn/table/column_width_calculator.rb +61 -0
- data/lib/prawn/table.rb +297 -118
- data/lib/prawn/text/box.rb +21 -5
- data/lib/prawn/text/formatted/arranger.rb +290 -0
- data/lib/prawn/text/formatted/box.rb +103 -59
- data/lib/prawn/text/formatted/fragment.rb +34 -23
- data/lib/prawn/text/formatted/line_wrap.rb +266 -0
- data/lib/prawn/text/formatted/parser.rb +15 -5
- data/lib/prawn/text/formatted/wrap.rb +150 -0
- data/lib/prawn/text/formatted.rb +5 -4
- data/lib/prawn/text.rb +38 -24
- data/lib/prawn/utilities.rb +46 -0
- data/lib/prawn.rb +85 -20
- data/manual/basic_concepts/adding_pages.rb +27 -0
- data/manual/basic_concepts/basic_concepts.rb +34 -0
- data/manual/basic_concepts/creation.rb +39 -0
- data/manual/basic_concepts/cursor.rb +33 -0
- data/manual/basic_concepts/measurement.rb +25 -0
- data/manual/basic_concepts/origin.rb +38 -0
- data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
- data/manual/bounding_box/bounding_box.rb +39 -0
- data/manual/bounding_box/bounds.rb +49 -0
- data/manual/bounding_box/canvas.rb +24 -0
- data/manual/bounding_box/creation.rb +23 -0
- data/manual/bounding_box/indentation.rb +46 -0
- data/manual/bounding_box/nesting.rb +45 -0
- data/manual/bounding_box/russian_boxes.rb +40 -0
- data/manual/bounding_box/stretchy.rb +31 -0
- data/manual/document_and_page_options/background.rb +27 -0
- data/manual/document_and_page_options/document_and_page_options.rb +32 -0
- data/manual/document_and_page_options/metadata.rb +23 -0
- data/manual/document_and_page_options/page_margins.rb +38 -0
- data/manual/document_and_page_options/page_size.rb +34 -0
- data/manual/document_and_page_options/print_scaling.rb +20 -0
- data/manual/example_file.rb +111 -0
- data/manual/example_helper.rb +411 -0
- data/manual/example_package.rb +53 -0
- data/manual/example_section.rb +46 -0
- data/manual/graphics/circle_and_ellipse.rb +22 -0
- data/manual/graphics/color.rb +24 -0
- data/manual/graphics/common_lines.rb +30 -0
- data/manual/graphics/fill_and_stroke.rb +42 -0
- data/manual/graphics/fill_rules.rb +37 -0
- data/manual/graphics/gradients.rb +37 -0
- data/manual/graphics/graphics.rb +58 -0
- data/manual/graphics/helper.rb +24 -0
- data/manual/graphics/line_width.rb +35 -0
- data/manual/graphics/lines_and_curves.rb +41 -0
- data/manual/graphics/polygon.rb +29 -0
- data/manual/graphics/rectangle.rb +21 -0
- data/manual/graphics/rotate.rb +28 -0
- data/manual/graphics/scale.rb +41 -0
- data/manual/graphics/soft_masks.rb +46 -0
- data/manual/graphics/stroke_cap.rb +31 -0
- data/manual/graphics/stroke_dash.rb +48 -0
- data/manual/graphics/stroke_join.rb +30 -0
- data/manual/graphics/translate.rb +29 -0
- data/manual/graphics/transparency.rb +35 -0
- data/manual/images/absolute_position.rb +23 -0
- data/manual/images/fit.rb +21 -0
- data/manual/images/horizontal.rb +25 -0
- data/manual/images/images.rb +40 -0
- data/manual/images/plain_image.rb +18 -0
- data/manual/images/scale.rb +22 -0
- data/manual/images/vertical.rb +28 -0
- data/manual/images/width_and_height.rb +25 -0
- data/manual/layout/boxes.rb +27 -0
- data/manual/layout/content.rb +25 -0
- data/manual/layout/layout.rb +28 -0
- data/manual/layout/simple_grid.rb +23 -0
- data/manual/manual/cover.rb +36 -0
- data/manual/manual/foreword.rb +85 -0
- data/manual/manual/how_to_read_this_manual.rb +41 -0
- data/manual/manual/manual.rb +34 -0
- data/manual/outline/add_subsection_to.rb +61 -0
- data/manual/outline/insert_section_after.rb +47 -0
- data/manual/outline/outline.rb +32 -0
- data/manual/outline/sections_and_pages.rb +67 -0
- data/manual/repeatable_content/page_numbering.rb +54 -0
- data/manual/repeatable_content/repeatable_content.rb +31 -0
- data/manual/repeatable_content/repeater.rb +55 -0
- data/manual/repeatable_content/stamp.rb +41 -0
- data/manual/security/encryption.rb +31 -0
- data/manual/security/permissions.rb +38 -0
- data/manual/security/security.rb +28 -0
- data/manual/syntax_highlight.rb +52 -0
- data/manual/table/basic_block.rb +53 -0
- data/manual/table/before_rendering_page.rb +26 -0
- data/manual/table/cell_border_lines.rb +24 -0
- data/manual/table/cell_borders_and_bg.rb +31 -0
- data/manual/table/cell_dimensions.rb +30 -0
- data/manual/table/cell_text.rb +38 -0
- data/manual/table/column_widths.rb +30 -0
- data/manual/table/content_and_subtables.rb +39 -0
- data/manual/table/creation.rb +27 -0
- data/manual/table/filtering.rb +36 -0
- data/manual/table/flow_and_header.rb +17 -0
- data/manual/table/image_cells.rb +33 -0
- data/manual/table/position.rb +29 -0
- data/manual/table/row_colors.rb +20 -0
- data/manual/table/span.rb +30 -0
- data/manual/table/style.rb +22 -0
- data/manual/table/table.rb +52 -0
- data/manual/table/width.rb +27 -0
- data/manual/text/alignment.rb +44 -0
- data/manual/text/color.rb +24 -0
- data/manual/text/column_box.rb +32 -0
- data/manual/text/fallback_fonts.rb +37 -0
- data/manual/text/font.rb +41 -0
- data/manual/text/font_size.rb +45 -0
- data/manual/text/font_style.rb +23 -0
- data/manual/text/formatted_callbacks.rb +60 -0
- data/manual/text/formatted_text.rb +54 -0
- data/manual/text/free_flowing_text.rb +51 -0
- data/manual/text/group.rb +31 -0
- data/manual/text/inline.rb +43 -0
- data/manual/text/kerning_and_character_spacing.rb +39 -0
- data/manual/text/leading.rb +25 -0
- data/manual/text/line_wrapping.rb +41 -0
- data/manual/text/paragraph_indentation.rb +26 -0
- data/manual/text/positioned_text.rb +38 -0
- data/manual/text/registering_families.rb +48 -0
- data/manual/text/rendering_and_color.rb +37 -0
- data/manual/text/right_to_left_text.rb +43 -0
- data/manual/text/rotation.rb +43 -0
- data/manual/text/single_usage.rb +37 -0
- data/manual/text/text.rb +75 -0
- data/manual/text/text_box_excess.rb +32 -0
- data/manual/text/text_box_extensions.rb +45 -0
- data/manual/text/text_box_overflow.rb +44 -0
- data/manual/text/utf8.rb +28 -0
- data/{examples/m17n → manual/text}/win_ansi_charset.rb +14 -10
- data/prawn.gemspec +27 -17
- data/spec/acceptance/png.rb +23 -0
- data/spec/annotations_spec.rb +16 -32
- data/spec/bounding_box_spec.rb +284 -2
- data/spec/cell_spec.rb +169 -38
- data/spec/column_box_spec.rb +65 -0
- data/spec/data/curves.pdf +66 -0
- data/spec/destinations_spec.rb +5 -5
- data/spec/document_spec.rb +212 -113
- data/spec/extensions/encoding_helpers.rb +9 -0
- data/spec/extensions/mocha.rb +2 -3
- data/spec/font_metric_cache_spec.rb +52 -0
- data/spec/font_spec.rb +205 -95
- data/spec/formatted_text_arranger_spec.rb +43 -43
- data/spec/formatted_text_box_spec.rb +63 -24
- data/spec/formatted_text_fragment_spec.rb +8 -8
- data/spec/graphics_spec.rb +175 -68
- data/spec/grid_spec.rb +26 -15
- data/spec/image_handler_spec.rb +54 -0
- data/spec/images_spec.rb +58 -30
- data/spec/inline_formatted_text_parser_spec.rb +73 -19
- data/spec/jpg_spec.rb +4 -4
- data/spec/line_wrap_spec.rb +28 -28
- data/spec/measurement_units_spec.rb +6 -6
- data/spec/object_store_spec.rb +17 -106
- data/spec/outline_spec.rb +103 -63
- data/spec/png_spec.rb +25 -25
- data/spec/reference_spec.rb +8 -65
- data/spec/repeater_spec.rb +25 -11
- data/spec/security_spec.rb +44 -12
- data/spec/snapshot_spec.rb +38 -6
- data/spec/soft_mask_spec.rb +117 -0
- data/spec/span_spec.rb +10 -15
- data/spec/spec_helper.rb +32 -8
- data/spec/stamp_spec.rb +29 -30
- data/spec/stroke_styles_spec.rb +36 -18
- data/spec/table/span_dummy_spec.rb +17 -0
- data/spec/table_spec.rb +850 -104
- data/spec/text_at_spec.rb +19 -33
- data/spec/text_box_spec.rb +117 -64
- data/spec/text_rendering_mode_spec.rb +5 -5
- data/spec/text_spacing_spec.rb +20 -2
- data/spec/text_spec.rb +111 -59
- data/spec/transparency_spec.rb +5 -5
- metadata +477 -328
- data/HACKING +0 -50
- data/README +0 -141
- data/data/fonts/Action Man.dfont +0 -0
- data/data/fonts/Activa.ttf +0 -0
- data/data/fonts/Chalkboard.ttf +0 -0
- data/data/fonts/DejaVuSans.ttf +0 -0
- data/data/fonts/Dustismo_Roman.ttf +0 -0
- data/data/fonts/comicsans.ttf +0 -0
- data/data/fonts/gkai00mp.ttf +0 -0
- data/data/images/16bit.dat +0 -0
- data/data/images/dice.dat +0 -0
- data/data/images/page_white_text.dat +0 -0
- data/data/images/rails.dat +0 -0
- data/data/images/rails.png +0 -0
- data/examples/bounding_box/bounding_boxes.rb +0 -44
- data/examples/bounding_box/indentation.rb +0 -35
- data/examples/bounding_box/russian_boxes.rb +0 -37
- data/examples/bounding_box/stretched_nesting.rb +0 -68
- data/examples/example_helper.rb +0 -8
- data/examples/general/background.rb +0 -24
- data/examples/general/canvas.rb +0 -16
- data/examples/general/context_sensitive_headers.rb +0 -38
- data/examples/general/float.rb +0 -12
- data/examples/general/margin.rb +0 -37
- data/examples/general/measurement_units.rb +0 -52
- data/examples/general/metadata-info.rb +0 -17
- data/examples/general/multi_page_layout.rb +0 -19
- data/examples/general/outlines.rb +0 -67
- data/examples/general/page_geometry.rb +0 -32
- data/examples/general/page_numbering.rb +0 -40
- data/examples/general/page_templates.rb +0 -20
- data/examples/general/repeaters.rb +0 -48
- data/examples/general/stamp.rb +0 -42
- data/examples/general/templates.rb +0 -14
- data/examples/graphics/basic_images.rb +0 -24
- data/examples/graphics/cmyk.rb +0 -13
- data/examples/graphics/curves.rb +0 -12
- data/examples/graphics/gradient.rb +0 -23
- data/examples/graphics/hexagon.rb +0 -14
- data/examples/graphics/image_fit.rb +0 -16
- data/examples/graphics/image_flow.rb +0 -38
- data/examples/graphics/image_position.rb +0 -18
- data/examples/graphics/line.rb +0 -33
- data/examples/graphics/png_types.rb +0 -23
- data/examples/graphics/polygons.rb +0 -17
- data/examples/graphics/remote_images.rb +0 -13
- data/examples/graphics/rounded_polygons.rb +0 -20
- data/examples/graphics/rounded_rectangle.rb +0 -21
- data/examples/graphics/ruport_style_helpers.rb +0 -20
- data/examples/graphics/stroke_bounds.rb +0 -21
- data/examples/graphics/stroke_cap_and_join.rb +0 -46
- data/examples/graphics/stroke_dash.rb +0 -43
- data/examples/graphics/transformations.rb +0 -53
- data/examples/graphics/transparency.rb +0 -27
- data/examples/grid/bounding_boxes.rb +0 -22
- data/examples/grid/column_gutter_grid.rb +0 -21
- data/examples/grid/multi_boxes.rb +0 -52
- data/examples/grid/show_grid.rb +0 -14
- data/examples/grid/simple_grid.rb +0 -21
- data/examples/m17n/chinese_text_wrapping.rb +0 -18
- data/examples/m17n/euro.rb +0 -16
- data/examples/m17n/full_win_ansi_character_list.rb +0 -20
- data/examples/m17n/sjis.rb +0 -29
- data/examples/m17n/utf8.rb +0 -14
- data/examples/security/hello_foo.rb +0 -9
- data/examples/table/bill.rb +0 -54
- data/examples/table/borders.rb +0 -25
- data/examples/table/cell.rb +0 -13
- data/examples/table/checkerboard.rb +0 -23
- data/examples/table/header.rb +0 -15
- data/examples/table/inline_format_table.rb +0 -13
- data/examples/table/multi_page_table.rb +0 -10
- data/examples/table/simple_table.rb +0 -25
- data/examples/table/subtable.rb +0 -13
- data/examples/table/widths.rb +0 -21
- data/examples/text/alignment.rb +0 -19
- data/examples/text/character_spacing.rb +0 -13
- data/examples/text/dfont.rb +0 -49
- data/examples/text/family_based_styling.rb +0 -25
- data/examples/text/font_calculations.rb +0 -92
- data/examples/text/font_size.rb +0 -34
- data/examples/text/hyphenation.rb +0 -45
- data/examples/text/indent_paragraphs.rb +0 -24
- data/examples/text/inline_format.rb +0 -104
- data/examples/text/kerning.rb +0 -31
- data/examples/text/rendering_mode.rb +0 -21
- data/examples/text/rotated.rb +0 -99
- data/examples/text/shaped_text_box.rb +0 -32
- data/examples/text/simple_text.rb +0 -18
- data/examples/text/simple_text_ttf.rb +0 -18
- data/examples/text/span.rb +0 -30
- data/examples/text/text_box.rb +0 -90
- data/examples/text/text_box_returning_excess.rb +0 -52
- data/examples/text/text_flow.rb +0 -68
- data/lib/prawn/compatibility.rb +0 -51
- data/lib/prawn/core/annotations.rb +0 -61
- data/lib/prawn/core/byte_string.rb +0 -9
- data/lib/prawn/core/destinations.rb +0 -90
- data/lib/prawn/core/document_state.rb +0 -78
- data/lib/prawn/core/literal_string.rb +0 -16
- data/lib/prawn/core/name_tree.rb +0 -165
- data/lib/prawn/core/object_store.rb +0 -264
- data/lib/prawn/core/page.rb +0 -213
- data/lib/prawn/core/pdf_object.rb +0 -108
- data/lib/prawn/core/reference.rb +0 -112
- data/lib/prawn/core/text/formatted/arranger.rb +0 -293
- data/lib/prawn/core/text/formatted/line_wrap.rb +0 -272
- data/lib/prawn/core/text/formatted/wrap.rb +0 -149
- data/lib/prawn/core/text.rb +0 -268
- data/lib/prawn/core.rb +0 -85
- data/lib/prawn/document/page_geometry.rb +0 -136
- data/lib/prawn/graphics/gradient.rb +0 -84
- data/spec/name_tree_spec.rb +0 -112
- data/spec/pdf_object_spec.rb +0 -170
- data/spec/template_spec.rb +0 -291
data/lib/prawn/text.rb
CHANGED
@@ -5,15 +5,18 @@
|
|
5
5
|
# Copyright May 2008, Gregory Brown. All Rights Reserved.
|
6
6
|
#
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
|
9
|
-
require "prawn/text/formatted"
|
10
|
-
require "prawn/text/box"
|
8
|
+
|
11
9
|
require "zlib"
|
12
10
|
|
11
|
+
require "pdf/core/text"
|
12
|
+
|
13
|
+
require_relative "text/formatted"
|
14
|
+
require_relative "text/box"
|
15
|
+
|
13
16
|
module Prawn
|
14
17
|
module Text
|
15
18
|
|
16
|
-
include
|
19
|
+
include PDF::Core::Text
|
17
20
|
include Prawn::Text::Formatted
|
18
21
|
|
19
22
|
# No-Break Space
|
@@ -23,11 +26,13 @@ module Prawn
|
|
23
26
|
# Soft Hyphen (invisible, except when causing a line break)
|
24
27
|
Prawn::Text::SHY = ""
|
25
28
|
|
29
|
+
# @group Stable API
|
30
|
+
|
26
31
|
# If you want text to flow onto a new page or between columns, this is the
|
27
32
|
# method to use. If, instead, if you want to place bounded text outside of
|
28
33
|
# the flow of a document (for captions, labels, charts, etc.), use Text::Box
|
29
34
|
# or its convenience method text_box.
|
30
|
-
#
|
35
|
+
#
|
31
36
|
# Draws text on the page. Prawn attempts to wrap the text to fit within your
|
32
37
|
# current bounding box (or margin_box if no bounding box is being used).
|
33
38
|
# Text will flow onto the next page when it reaches the bottom of the
|
@@ -49,28 +54,29 @@ module Prawn
|
|
49
54
|
# entire document, set default_kerning = false for that document
|
50
55
|
#
|
51
56
|
# === Text Positioning Details
|
52
|
-
#
|
57
|
+
#
|
53
58
|
# The text is positioned at font.ascender below the baseline,
|
54
59
|
# making it easy to use this method within bounding boxes and spans.
|
55
60
|
#
|
56
61
|
# == Encoding
|
57
62
|
#
|
58
63
|
# Note that strings passed to this function should be encoded as UTF-8.
|
59
|
-
# If you get unexpected characters appearing in your rendered document,
|
64
|
+
# If you get unexpected characters appearing in your rendered document,
|
60
65
|
# check this.
|
61
66
|
#
|
62
67
|
# If the current font is a built-in one, although the string must be
|
63
68
|
# encoded as UTF-8, only characters that are available in WinAnsi
|
64
69
|
# are allowed.
|
65
70
|
#
|
66
|
-
# If an empty box is rendered to your PDF instead of the character you
|
71
|
+
# If an empty box is rendered to your PDF instead of the character you
|
67
72
|
# wanted it usually means the current font doesn't include that character.
|
68
73
|
#
|
69
74
|
# == Options (default values marked in [])
|
70
75
|
#
|
71
76
|
# <tt>:inline_format</tt>::
|
72
77
|
# <tt>boolean</tt>. If true, then the string parameter is interpreted
|
73
|
-
# as a HTML-esque string that recognizes the following tags
|
78
|
+
# as a HTML-esque string that recognizes the following tags
|
79
|
+
# (assuming the default text formatter is used):
|
74
80
|
# <tt>\<b></b></tt>:: bold
|
75
81
|
# <tt>\<i></i></tt>:: italic
|
76
82
|
# <tt>\<u></u></tt>:: underline
|
@@ -97,8 +103,8 @@ module Prawn
|
|
97
103
|
# <tt>anchor="ToC"</tt>::
|
98
104
|
# where the value of the anchor attribute is the name of a
|
99
105
|
# destination that has already been or will be registered
|
100
|
-
# using
|
101
|
-
# will be created to that destination.
|
106
|
+
# using PDF::Core::Destinations#add_dest. A clickable link
|
107
|
+
# will be created to that destination.
|
102
108
|
# Note that you must explicitly underline and color using the
|
103
109
|
# appropriate tags if you which to draw attention to the link
|
104
110
|
#
|
@@ -107,6 +113,7 @@ module Prawn
|
|
107
113
|
# [value of document.default_kerning?]
|
108
114
|
# <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
|
109
115
|
# size]
|
116
|
+
# <tt>:color</tt>:: an RGB color ("ff0000") or CMYK array [10, 20, 30, 40].
|
110
117
|
# <tt>:character_spacing</tt>:: <tt>number</tt>. The amount of space to add
|
111
118
|
# to or remove from the default character
|
112
119
|
# spacing. [0]
|
@@ -142,7 +149,7 @@ module Prawn
|
|
142
149
|
# text should render with the fill color, stroke color or
|
143
150
|
# both. See the comments to text_rendering_mode() to see
|
144
151
|
# a list of valid options. [0]
|
145
|
-
#
|
152
|
+
#
|
146
153
|
# == Exceptions
|
147
154
|
#
|
148
155
|
# Raises <tt>ArgumentError</tt> if <tt>:at</tt> option included
|
@@ -151,12 +158,14 @@ module Prawn
|
|
151
158
|
# any text
|
152
159
|
#
|
153
160
|
def text(string, options={})
|
161
|
+
return false if string.nil?
|
154
162
|
# we modify the options. don't change the user's hash
|
155
163
|
options = options.dup
|
156
164
|
|
157
|
-
if options[:inline_format]
|
165
|
+
if p = options[:inline_format]
|
166
|
+
p = [] unless p.is_a?(Array)
|
158
167
|
options.delete(:inline_format)
|
159
|
-
array =
|
168
|
+
array = self.text_formatter.format(string, *p)
|
160
169
|
else
|
161
170
|
array = [{ :text => string }]
|
162
171
|
end
|
@@ -164,7 +173,6 @@ module Prawn
|
|
164
173
|
formatted_text(array, options)
|
165
174
|
end
|
166
175
|
|
167
|
-
|
168
176
|
# Draws formatted text to the page.
|
169
177
|
# Formatted text is comprised of an array of hashes, where each hash defines
|
170
178
|
# text and format information. See Text::Formatted#formatted_text_box for
|
@@ -175,7 +183,7 @@ module Prawn
|
|
175
183
|
# text([{ :text => "hello" },
|
176
184
|
# { :text => "world",
|
177
185
|
# :size => 24,
|
178
|
-
# :
|
186
|
+
# :styles => [:bold, :italic] }])
|
179
187
|
#
|
180
188
|
# == Options
|
181
189
|
#
|
@@ -188,8 +196,14 @@ module Prawn
|
|
188
196
|
def formatted_text(array, options={})
|
189
197
|
options = inspect_options_for_text(options.dup)
|
190
198
|
|
199
|
+
if color = options.delete(:color)
|
200
|
+
array = array.map do |fragment|
|
201
|
+
fragment[:color] ? fragment : fragment.merge(:color => color)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
191
205
|
if @indent_paragraphs
|
192
|
-
|
206
|
+
self.text_formatter.array_paragraphs(array).each do |paragraph|
|
193
207
|
options[:skip_encoding] = false
|
194
208
|
remaining_text = draw_indented_formatted_line(paragraph, options)
|
195
209
|
options[:skip_encoding] = true
|
@@ -216,7 +230,7 @@ module Prawn
|
|
216
230
|
|
217
231
|
# Draws text on the page, beginning at the point specified by the :at option
|
218
232
|
# the string is assumed to be pre-formatted to properly fit the page.
|
219
|
-
#
|
233
|
+
#
|
220
234
|
# pdf.draw_text "Hello World", :at => [100,100]
|
221
235
|
# pdf.draw_text "Goodbye World", :at => [50,50], :size => 16
|
222
236
|
#
|
@@ -238,14 +252,14 @@ module Prawn
|
|
238
252
|
# == Encoding
|
239
253
|
#
|
240
254
|
# Note that strings passed to this function should be encoded as UTF-8.
|
241
|
-
# If you get unexpected characters appearing in your rendered document,
|
255
|
+
# If you get unexpected characters appearing in your rendered document,
|
242
256
|
# check this.
|
243
257
|
#
|
244
258
|
# If the current font is a built-in one, although the string must be
|
245
259
|
# encoded as UTF-8, only characters that are available in WinAnsi
|
246
260
|
# are allowed.
|
247
261
|
#
|
248
|
-
# If an empty box is rendered to your PDF instead of the character you
|
262
|
+
# If an empty box is rendered to your PDF instead of the character you
|
249
263
|
# wanted it usually means the current font doesn't include that character.
|
250
264
|
#
|
251
265
|
# == Options (default values marked in [])
|
@@ -274,7 +288,7 @@ module Prawn
|
|
274
288
|
text = text.to_s.dup
|
275
289
|
save_font do
|
276
290
|
process_text_options(options)
|
277
|
-
font.normalize_encoding!(text)
|
291
|
+
font.normalize_encoding!(text)
|
278
292
|
font_size(options[:size]) { draw_text!(text, options) }
|
279
293
|
end
|
280
294
|
end
|
@@ -307,7 +321,7 @@ module Prawn
|
|
307
321
|
# height_of_formatted([{ :text => "hello" },
|
308
322
|
# { :text => "world",
|
309
323
|
# :size => 24,
|
310
|
-
# :
|
324
|
+
# :styles => [:bold, :italic] }])
|
311
325
|
#
|
312
326
|
def height_of_formatted(array, options={})
|
313
327
|
if options[:indent_paragraphs]
|
@@ -318,7 +332,7 @@ module Prawn
|
|
318
332
|
box = Text::Formatted::Box.new(array,
|
319
333
|
options.merge(:height => 100000000,
|
320
334
|
:document => self))
|
321
|
-
|
335
|
+
box.render(:dry_run => true)
|
322
336
|
|
323
337
|
height = box.height
|
324
338
|
height += box.line_gap + box.leading if @final_gap
|
@@ -374,7 +388,7 @@ module Prawn
|
|
374
388
|
if options[:kerning].nil? then
|
375
389
|
options[:kerning] = default_kerning?
|
376
390
|
end
|
377
|
-
valid_options =
|
391
|
+
valid_options = PDF::Core::Text::VALID_OPTIONS + [:at, :rotate]
|
378
392
|
Prawn.verify_options(valid_options, options)
|
379
393
|
options
|
380
394
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# utilities.rb : General-purpose utility classes which don't fit anywhere else
|
4
|
+
#
|
5
|
+
# Copyright August 2012, Alex Dowad. All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
+
|
9
|
+
require 'thread'
|
10
|
+
|
11
|
+
module Prawn
|
12
|
+
|
13
|
+
# Throughout the Prawn codebase, repeated calculations which can benefit from caching are made
|
14
|
+
# In some cases, caching and reusing results can not only save CPU cycles but also greatly
|
15
|
+
# reduce memory requirements
|
16
|
+
# But at the same time, we don't want to throw away thread safety
|
17
|
+
# We have two interchangeable thread-safe cache implementations:
|
18
|
+
|
19
|
+
# @private
|
20
|
+
class SynchronizedCache
|
21
|
+
# As an optimization, this could access the hash directly on VMs with a global interpreter lock (like MRI)
|
22
|
+
def initialize
|
23
|
+
@cache = {}
|
24
|
+
@mutex = Mutex.new
|
25
|
+
end
|
26
|
+
def [](key)
|
27
|
+
@mutex.synchronize { @cache[key] }
|
28
|
+
end
|
29
|
+
def []=(key,value)
|
30
|
+
@mutex.synchronize { @cache[key] = value }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @private
|
35
|
+
class ThreadLocalCache
|
36
|
+
def initialize
|
37
|
+
@cache_id = "cache_#{self.object_id}".to_sym
|
38
|
+
end
|
39
|
+
def [](key)
|
40
|
+
(Thread.current[@cache_id] ||= {})[key]
|
41
|
+
end
|
42
|
+
def []=(key,value)
|
43
|
+
(Thread.current[@cache_id] ||= {})[key] = value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/prawn.rb
CHANGED
@@ -1,26 +1,91 @@
|
|
1
1
|
# Welcome to Prawn, the best PDF Generation library ever.
|
2
2
|
# This documentation covers user level functionality.
|
3
3
|
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
require "set"
|
5
|
+
|
6
|
+
require 'ttfunk'
|
7
|
+
require "pdf/core"
|
8
|
+
|
9
|
+
module Prawn
|
10
|
+
VERSION = "0.15.0"
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
file = __FILE__
|
15
|
+
file = File.readlink(file) if File.symlink?(file)
|
16
|
+
dir = File.dirname(file)
|
17
|
+
|
18
|
+
# The base source directory for Prawn as installed on the system
|
19
|
+
#
|
20
|
+
#
|
21
|
+
BASEDIR = File.expand_path(File.join(dir, '..'))
|
22
|
+
DATADIR = File.expand_path(File.join(dir, '..', 'data'))
|
23
|
+
|
24
|
+
FLOAT_PRECISION = 1.0e-9
|
25
|
+
|
26
|
+
# Whe set to true, Prawn will verify hash options to ensure only valid keys
|
27
|
+
# are used. Off by default.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# >> Prawn::Document.new(:tomato => "Juicy")
|
31
|
+
# Prawn::Errors::UnknownOption:
|
32
|
+
# Detected unknown option(s): [:tomato]
|
33
|
+
# Accepted options are: [:page_size, :page_layout, :left_margin, ...]
|
34
|
+
#
|
35
|
+
attr_accessor :debug # @private
|
36
|
+
|
37
|
+
def verify_options(accepted, actual) # @private
|
38
|
+
return unless debug || $DEBUG
|
39
|
+
unless (act=Set[*actual.keys]).subset?(acc=Set[*accepted])
|
40
|
+
raise Prawn::Errors::UnknownOption,
|
41
|
+
"\nDetected unknown option(s): #{(act - acc).to_a.inspect}\n" <<
|
42
|
+
"Accepted options are: #{accepted.inspect}"
|
43
|
+
end
|
44
|
+
yield if block_given?
|
45
|
+
end
|
46
|
+
|
47
|
+
module Configurable # @private
|
48
|
+
def configuration(*args)
|
49
|
+
@config ||= Marshal.load(Marshal.dump(default_configuration))
|
50
|
+
if Hash === args[0]
|
51
|
+
@config.update(args[0])
|
52
|
+
elsif args.length > 1
|
53
|
+
@config.values_at(*args)
|
54
|
+
elsif args.length == 1
|
55
|
+
@config[args[0]]
|
56
|
+
else
|
57
|
+
@config
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
alias_method :C, :configuration
|
62
|
+
end
|
9
63
|
end
|
10
64
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
65
|
+
require_relative "prawn/errors"
|
66
|
+
|
67
|
+
|
68
|
+
require_relative "prawn/utilities"
|
69
|
+
require_relative "prawn/text"
|
70
|
+
require_relative "prawn/graphics"
|
71
|
+
require_relative "prawn/images"
|
72
|
+
require_relative "prawn/images/image"
|
73
|
+
require_relative "prawn/images/jpg"
|
74
|
+
require_relative "prawn/images/png"
|
75
|
+
require_relative "prawn/stamp"
|
76
|
+
require_relative "prawn/soft_mask"
|
77
|
+
require_relative "prawn/security"
|
78
|
+
require_relative "prawn/document"
|
79
|
+
require_relative "prawn/font"
|
80
|
+
require_relative "prawn/encoding"
|
81
|
+
require_relative "prawn/measurements"
|
82
|
+
require_relative "prawn/repeater"
|
83
|
+
require_relative "prawn/outline"
|
84
|
+
require_relative "prawn/layout"
|
85
|
+
|
86
|
+
require_relative "prawn/image_handler"
|
87
|
+
|
88
|
+
|
26
89
|
|
90
|
+
Prawn.image_handler.register(Prawn::Images::PNG)
|
91
|
+
Prawn.image_handler.register(Prawn::Images::JPG)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# A PDF document is a collection of pages. When we create a new document be it
|
4
|
+
# with <code>Document.new</code> or on a <code>Document.generate</code> block
|
5
|
+
# one initial page is created for us.
|
6
|
+
#
|
7
|
+
# Some methods might create new pages automatically like <code>text</code> which
|
8
|
+
# will create a new page whenever the text string cannot fit on the current
|
9
|
+
# page.
|
10
|
+
#
|
11
|
+
# But what if you want to go to the next page by yourself? That is easy.
|
12
|
+
#
|
13
|
+
# Just use the <code>start_new_page</code> method and a shiny new page will be
|
14
|
+
# created for you just like in the following snippet.
|
15
|
+
#
|
16
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
17
|
+
%w[.. example_helper]))
|
18
|
+
|
19
|
+
filename = File.basename(__FILE__).gsub('.rb', '.pdf')
|
20
|
+
Prawn::Example.generate(filename) do
|
21
|
+
text "We are still on the initial page for this example. Now I'll ask " +
|
22
|
+
"Prawn to gently start a new page. Please follow me to the next page."
|
23
|
+
|
24
|
+
start_new_page
|
25
|
+
|
26
|
+
text "See. We've left the previous page behind."
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Examples for Prawn basic concepts.
|
4
|
+
#
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
6
|
+
%w[.. example_helper]))
|
7
|
+
|
8
|
+
Prawn::Example.generate("basic_concepts.pdf", :page_size => "FOLIO") do
|
9
|
+
|
10
|
+
package "basic_concepts" do |p|
|
11
|
+
|
12
|
+
p.example "creation", :eval_source => false, :full_source => true
|
13
|
+
p.example "origin"
|
14
|
+
p.example "cursor"
|
15
|
+
p.example "other_cursor_helpers"
|
16
|
+
p.example "adding_pages"
|
17
|
+
p.example "measurement"
|
18
|
+
|
19
|
+
p.intro do
|
20
|
+
prose("This chapter covers the minimum amount of functionality you'll need to start using Prawn.
|
21
|
+
|
22
|
+
If you are new to Prawn this is the first chapter to read. Once you are comfortable with the concepts shown here you might want to check the Basics section of the Graphics, Bounding Box and Text sections.
|
23
|
+
|
24
|
+
The examples show:")
|
25
|
+
|
26
|
+
list( "How to create new pdf documents in every possible way",
|
27
|
+
"Where the origin for the document coordinates is. What are Bounding Boxes and how they interact with the origin",
|
28
|
+
"How the cursor behaves",
|
29
|
+
"How to start new pages",
|
30
|
+
"What the base unit for measurement and coordinates is and how to use other convenient measures"
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# There are three ways to create a PDF Document in Prawn: creating a new
|
4
|
+
# <code>Prawn::Document</code> instance, or using the
|
5
|
+
# <code>Prawn::Document.generate</code> method with and without block arguments.
|
6
|
+
#
|
7
|
+
# The following snippet showcase each way by creating a simple document with
|
8
|
+
# some text drawn.
|
9
|
+
#
|
10
|
+
# When we instantiate the <code>Prawn::Document</code> object the actual pdf
|
11
|
+
# document will only be created after we call <code>render_file</code>.
|
12
|
+
#
|
13
|
+
# The generate method will render the actual pdf object after exiting the block.
|
14
|
+
# When we use it without a block argument the provided block is evaluated in the
|
15
|
+
# context of a newly created <code>Prawn::Document</code> instance. When we use
|
16
|
+
# it with a block argument a <code>Prawn::Document</code> instance is created
|
17
|
+
# and passed to the block.
|
18
|
+
#
|
19
|
+
# The generate method without block arguments requires
|
20
|
+
# less typing and defines and renders the pdf document in one shot.
|
21
|
+
# Almost all of the examples are coded this way.
|
22
|
+
#
|
23
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
24
|
+
%w[.. example_helper]))
|
25
|
+
|
26
|
+
# Assignment
|
27
|
+
pdf = Prawn::Document.new
|
28
|
+
pdf.text "Hello World"
|
29
|
+
pdf.render_file "assignment.pdf"
|
30
|
+
|
31
|
+
# Implicit Block
|
32
|
+
Prawn::Document.generate("implicit.pdf") do
|
33
|
+
text "Hello World"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Explicit Block
|
37
|
+
Prawn::Document.generate("explicit.pdf") do |pdf|
|
38
|
+
pdf.text "Hello World"
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# We normally write our documents from top to bottom and it is no different with
|
4
|
+
# Prawn. Even if the origin is on the bottom left corner we still fill the page
|
5
|
+
# from the top to the bottom. In other words the cursor for inserting content
|
6
|
+
# starts on the top of the page.
|
7
|
+
#
|
8
|
+
# Most of the functions that insert content on the page will start at the
|
9
|
+
# current cursor position and proceed to the bottom of the page.
|
10
|
+
#
|
11
|
+
# The following snippet shows how the cursor behaves when we add some text to
|
12
|
+
# the page and demonstrates some of the helpers to manage the cursor position.
|
13
|
+
# The <code>cursor</code> method returns the current cursor position.
|
14
|
+
#
|
15
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
16
|
+
%w[.. example_helper]))
|
17
|
+
|
18
|
+
filename = File.basename(__FILE__).gsub('.rb', '.pdf')
|
19
|
+
Prawn::Example.generate(filename) do
|
20
|
+
stroke_axis
|
21
|
+
|
22
|
+
text "the cursor is here: #{cursor}"
|
23
|
+
text "now it is here: #{cursor}"
|
24
|
+
|
25
|
+
move_down 200
|
26
|
+
text "on the first move the cursor went down to: #{cursor}"
|
27
|
+
|
28
|
+
move_up 100
|
29
|
+
text "on the second move the cursor went up to: #{cursor}"
|
30
|
+
|
31
|
+
move_cursor_to 50
|
32
|
+
text "on the last move the cursor went directly to: #{cursor}"
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# The base unit in Prawn is the PDF Point. One PDF Point is equal to 1/72 of
|
4
|
+
# an inch.
|
5
|
+
#
|
6
|
+
# There is no need to waste time converting this measures. Prawn provides
|
7
|
+
# helpers for converting from other measurements
|
8
|
+
# to PDF Points.
|
9
|
+
#
|
10
|
+
# Just <code>require "prawn/measurement_extensions"</code> and it will mix some
|
11
|
+
# helpers onto <code>Numeric</code> for converting common measurement units to
|
12
|
+
# PDF Points.
|
13
|
+
#
|
14
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
15
|
+
%w[.. example_helper]))
|
16
|
+
|
17
|
+
filename = File.basename(__FILE__).gsub('.rb', '.pdf')
|
18
|
+
Prawn::Example.generate(filename) do
|
19
|
+
require "prawn/measurement_extensions"
|
20
|
+
|
21
|
+
[:mm, :cm, :dm, :m, :in, :yd, :ft].each do |measurement|
|
22
|
+
text "1 #{measurement} in PDF Points: #{1.send(measurement)} pt"
|
23
|
+
move_down 5.mm
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This is the most important concept you need to learn about Prawn:
|
4
|
+
#
|
5
|
+
# PDF documents have the origin <code>[0,0]</code> at the bottom-left corner of
|
6
|
+
# the page.
|
7
|
+
#
|
8
|
+
# A bounding box is a structure which provides boundaries for inserting content.
|
9
|
+
# A bounding box also has the property of relocating the origin to its relative
|
10
|
+
# bottom-left corner. However, be aware that the location specified when
|
11
|
+
# creating a bounding box is its top-left corner, not bottom-left (hence the
|
12
|
+
# <code>[100, 300]</code> coordinates below).
|
13
|
+
#
|
14
|
+
# Even if you never create a bounding box explictly, each document already comes
|
15
|
+
# with one called the margin box. This initial bounding box is the one
|
16
|
+
# responsible for the document margins.
|
17
|
+
#
|
18
|
+
# So practically speaking the origin of a page on a default generated document
|
19
|
+
# isn't the absolute bottom left corner but the bottom left corner of the margin
|
20
|
+
# box.
|
21
|
+
#
|
22
|
+
# The following snippet strokes a circle on the margin box origin. Then strokes
|
23
|
+
# the boundaries of a bounding box and a circle on its origin.
|
24
|
+
#
|
25
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
26
|
+
%w[.. example_helper]))
|
27
|
+
|
28
|
+
filename = File.basename(__FILE__).gsub('.rb', '.pdf')
|
29
|
+
Prawn::Example.generate(filename) do
|
30
|
+
stroke_axis
|
31
|
+
|
32
|
+
stroke_circle [0, 0], 10
|
33
|
+
|
34
|
+
bounding_box([100, 300], :width => 300, :height => 200) do
|
35
|
+
stroke_bounds
|
36
|
+
stroke_circle [0, 0], 10
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Another group of helpers for changing the cursor position are the pad methods.
|
4
|
+
# They accept a numeric value and a block. <code>pad</code> will use the numeric
|
5
|
+
# value to move the cursor down both before and after the block content.
|
6
|
+
# <code>pad_top</code> will only move the cursor before the block while
|
7
|
+
# <code>pad_bottom</code> will only move after.
|
8
|
+
#
|
9
|
+
# <code>float</code> is a method for not changing the cursor. Pass it a block
|
10
|
+
# and the cursor will remain on the same place when the block returns.
|
11
|
+
#
|
12
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
13
|
+
%w[.. example_helper]))
|
14
|
+
|
15
|
+
filename = File.basename(__FILE__).gsub('.rb', '.pdf')
|
16
|
+
Prawn::Example.generate(filename) do
|
17
|
+
stroke_horizontal_rule
|
18
|
+
pad(20) { text "Text padded both before and after." }
|
19
|
+
|
20
|
+
stroke_horizontal_rule
|
21
|
+
pad_top(20) { text "Text padded on the top." }
|
22
|
+
|
23
|
+
stroke_horizontal_rule
|
24
|
+
pad_bottom(20) { text "Text padded on the bottom." }
|
25
|
+
|
26
|
+
stroke_horizontal_rule
|
27
|
+
move_down 30
|
28
|
+
|
29
|
+
text "Text written before the float block."
|
30
|
+
|
31
|
+
float do
|
32
|
+
move_down 30
|
33
|
+
bounding_box([0, cursor], :width => 200) do
|
34
|
+
text "Text written inside the float block."
|
35
|
+
stroke_bounds
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
text "Text written after the float block."
|
40
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Examples for bounding boxes.
|
4
|
+
#
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__),
|
6
|
+
%w[.. example_helper]))
|
7
|
+
|
8
|
+
Prawn::Example.generate("bounding_box.pdf", :page_size => "FOLIO") do
|
9
|
+
|
10
|
+
package "bounding_box" do |p|
|
11
|
+
|
12
|
+
p.section "Basics" do |s|
|
13
|
+
s.example "creation"
|
14
|
+
s.example "bounds"
|
15
|
+
end
|
16
|
+
|
17
|
+
p.section "Advanced" do |s|
|
18
|
+
s.example "stretchy"
|
19
|
+
s.example "nesting"
|
20
|
+
s.example "indentation"
|
21
|
+
s.example "canvas"
|
22
|
+
s.example "russian_boxes"
|
23
|
+
end
|
24
|
+
|
25
|
+
p.intro do
|
26
|
+
prose("Bounding boxes are the basic containers for structuring the content flow. Even being low level building blocks sometimes their simplicity is very welcome.
|
27
|
+
|
28
|
+
The examples show:")
|
29
|
+
|
30
|
+
list( "How to create bounding boxes with specific dimensions",
|
31
|
+
"How to inspect the current bounding box for its coordinates",
|
32
|
+
"Stretchy bounding boxes",
|
33
|
+
"Nested bounding boxes",
|
34
|
+
"Indent blocks"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|