Code

f0783c149b6dc846895089d191e3cf37e6d05618
[inkscape.git] / src / libnrtype / Layout-TNG-Scanline-Maker.h
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;
61     
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     virtual ~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
121 public:
122     ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression);
123     virtual ~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 :