1 /*
2 * Inkscape::Text::Layout::ScanlineMaker - text layout engine shape measurers
3 *
4 * Authors:
5 * Richard Hughes <cyreve@users.sf.net>
6 *
7 * Copyright (C) 2005 Richard Hughes
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
11 #ifndef __LAYOUT_TNG_SCANLINE_MAKER_H__
12 #define __LAYOUT_TNG_SCANLINE_MAKER_H__
14 #include <vector>
15 #include <cmath>
16 #include "libnrtype/Layout-TNG.h"
18 class Shape;
20 namespace Inkscape {
21 namespace Text {
23 /** \brief private to Layout. Generates lists of chunks within a shape.
25 This is the abstract base class for taking a given shape and scanning through
26 it line-by-line to get the horizontal extents of each chunk for a line of a
27 given height. There are two specialisations: One for real shapes and one that
28 turns off wrapping by simulating an infinite shape. In due course there will
29 be a further specialisation to optimise for the common case where the shape
30 is a rectangle.
31 */
32 class Layout::ScanlineMaker
33 {
34 public:
35 virtual ~ScanlineMaker() {}
37 struct ScanRun {
38 double y; /// that's the top of the scan run, not the baseline
39 double x_start; // these are not flipped according to the text direction
40 double x_end;
41 inline double width() const {return std::abs(x_start - x_end);}
42 };
44 /** Returns a list of chunks on the current line which can fit text with
45 the given properties. It is up to the caller to discard any chunks which
46 are too narrow for its needs. This function may change the y coordinate
47 between calls if the new height too big to fit in the space remaining in
48 this shape. Returns an empty vector if there is no space left in the
49 current shape. */
50 virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height) =0;
52 /** Indicates that the caller has successfully filled the current line
53 and hence that the next call to makeScanline() should return lines on
54 the next lower line. There is no error return, the next call to
55 makeScanline() will give an error if there is no more space. */
56 virtual void completeLine() =0;
58 /** Returns the y coordinate of the top of the scanline that will be
59 returned by the next call to makeScanline(). */
60 virtual double yCoordinate() = 0;
62 /** Forces an arbitrary change in the stored y coordinate of the object.
63 The next call to makeScanline() will return runs whose top is at
64 the new coordinate. */
65 virtual void setNewYCoordinate(double new_y) =0;
67 /** Tests whether the caller can fit a new line with the given metrics
68 into exactly the space returned by the previous call to makeScanline().
69 This saves the caller from having to discard its wrapping solution and
70 starting at the beginning of the line again when a larger font is seen.
71 The metrics given here are considered to be the ones that are being
72 used now, and hence is the line advance height used by completeLine().
73 */
74 virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height) =0;
75 };
77 /** \brief private to Layout. Generates infinite scanlines for when you don't want wrapping
79 This is a 'fake' scanline maker which will always return infinite results,
80 effectively turning off wrapping. It's a very simple implementation.
82 It does have the curious property, however, that the input coordinates are
83 'real' x and y, but the outputs are rotated according to the
84 \a block_progression.
85 */
86 class Layout::InfiniteScanlineMaker : public Layout::ScanlineMaker
87 {
88 public:
89 InfiniteScanlineMaker(double initial_x, double initial_y, Layout::Direction block_progression);
90 ~InfiniteScanlineMaker();
92 /** Returns a single infinite run at the current location */
93 virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height);
95 /** Increments the current y by the current line height */
96 virtual void completeLine();
98 virtual double yCoordinate()
99 {return _y;}
101 /** Just changes y */
102 virtual void setNewYCoordinate(double new_y);
104 /** Always true, but has to save the new height */
105 virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height);
107 private:
108 double _x, _y;
109 Layout::LineHeight _current_line_height;
110 bool _negative_block_progression; /// if true, indicates that completeLine() should decrement rather than increment, ie block-progression is either rl or bt
111 };
113 /** \brief private to Layout. Generates scanlines inside an arbitrary shape
115 This is the 'perfect', and hence slowest, implementation of a
116 Layout::ScanlineMaker, which will return exact bounds for any given
117 input shape.
118 */
119 class Layout::ShapeScanlineMaker : public Layout::ScanlineMaker
120 {
121 public:
122 ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression);
123 ~ShapeScanlineMaker();
125 virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height);
127 virtual void completeLine();
129 virtual double yCoordinate();
131 virtual void setNewYCoordinate(double new_y);
133 /** never true */
134 virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height);
135 private:
136 /** To generate scanlines for top-to-bottom text it is easiest if we
137 simply rotate the given shape by a multiple of 90 degrees. This stores
138 that. If no rotation was needed we can simply store the pointer we were
139 given and set shape_needs_freeing appropriately. */
140 Shape *_rotated_shape;
142 /// see #rotated_shape;
143 bool _shape_needs_freeing;
145 // Shape::BeginRaster() needs floats rather than doubles
146 float _bounding_box_top, _bounding_box_bottom;
147 float _y;
148 float _rasterizer_y;
149 int _current_rasterization_point;
150 float _current_line_height;
152 bool _negative_block_progression; /// if true, indicates that completeLine() should decrement rather than increment, ie block-progression is either rl or bt
153 };
155 }//namespace Text
156 }//namespace Inkscape
158 #endif
160 /*
161 Local Variables:
162 mode:c++
163 c-file-style:"stroustrup"
164 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
165 indent-tabs-mode:nil
166 fill-column:99
167 End:
168 */
169 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :