Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / libnrtype / Layout-TNG.h
1 /*
2  * Inkscape::Text::Layout - text layout engine
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_H__
12 #define __LAYOUT_TNG_H__
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17 #include <libnr/nr-matrix-ops.h>
18 #include <libnr/nr-rotate-ops.h>
19 #include <libnr/nr-rect.h>
20 #include <2geom/d2.h>
21 #include <2geom/matrix.h>
22 #include <glibmm/ustring.h>
23 #include <pango/pango-break.h>
24 #include <algorithm>
25 #include <vector>
26 #include <boost/optional.hpp>
28 #ifdef HAVE_CAIRO_PDF
29 namespace Inkscape {
30         namespace Extension {
31                 namespace Internal {
32                         class CairoRenderContext;
33                 }
34         }
35 }
37 using Inkscape::Extension::Internal::CairoRenderContext;
38 #endif
40 class SPStyle;
41 class Shape;
42 class NRArenaGroup;
43 class SPPrintContext;
44 class SVGLength;
45 class Path;
46 class SPCurve;
47 class font_instance;
48 typedef struct _PangoFontDescription PangoFontDescription;
50 namespace Inkscape {
51 namespace Text {
53 /** \brief Generates the layout for either wrapped or non-wrapped text and stores the result
55 Use this class for all your text output needs. It takes text with formatting
56 markup as input and turns that into the glyphs and their necessary positions.
57 It stores the glyphs internally, but maintains enough information to both
58 retrieve your own rendering information if you wish and to perform visual
59 text editing where the output refers back to where it came from.
61 Usage:
62 -# Construct
63 -# Set the text using appendText() and appendControlCode()
64 -# If you want text wrapping, call appendWrapShape() a few times
65 -# Call calculateFlow()
66 -# You can go several directions from here, but the most interesting
67    things start with creating a Layout::iterator with begin() or end().
69 Terminology, in descending order of size:
70 - Flow: Not often used, but when it is it means all the text
71 - Shape: A Shape object which is used to represent one of the regions inside
72   which to flow the text. Can overlap with...
73 - Paragraph: Err...A paragraph. Contains one or more...
74 - Line: An entire horizontal line with a common baseline. Contains one or
75   more...
76 - Chunk: You only get more than one of these when a shape is sufficiently
77   complex that the text has to flow either side of some obstruction in
78   the middle. A chunk is the base unit for wrapping. Contains one or more...
79 - Span: A convenient subset of a chunk with the same font, style,
80   directionality, block progression and input stream. Fill and outline
81   need not be constant because that's a later rendering stage.
82 - This is where it gets weird because a span will contain one or more 
83   elements of both of the following, which can overlap with each other in
84   any way:
85   - Character: a single Unicode codepoint from an input stream. Many arabic
86     characters contain multiple glyphs
87   - Glyph: a rendering primitive for font engines. A ligature glyph will
88     represent multiple characters.
90 Other terminology:
91 - Input stream: An object representing a single call to appendText() or
92   appendControlCode().
93 - Control code: Metadata in the text stream to signify items that occupy
94   real space (unlike style changes) but don't belong in the text string.
95   Paragraph breaks are in this category. See Layout::TextControlCode.
96 - SVG1.1: The W3C Recommendation "Scalable Vector Graphics (SVG) 1.1"
97   http://www.w3.org/TR/SVG11/
98 - 'left', 'down', etc: These terms are generally used to mean what they
99   mean in left-to-right, top-to-bottom text but rotated or reflected for
100   the current directionality. Thus, the 'width' of a ttb line is actually
101   its height, and the (internally stored) y coordinate of a glyph is
102   actually its x coordinate. Confusing to the reader but much simpler in
103   the code. All public methods use real x and y.
105 Comments:
106 - There's a strong emphasis on international support in this class, but
107   that's primarily because once you can display all the insane things
108   required by various languages, simple things like styling text are
109   almost trivial.
110 - There are a few places (appendText() is one) where pointers are held to
111   caller-owned objects and used for quite a long time. This is messy but
112   is safe for our usage scenario and in many cases the cost of copying the
113   objects is quite high.
114 - "Why isn't foo here?": Ask yourself if it's possible to implement foo
115   externally using iterators. However this may not mean that it doesn't
116   belong as a member, though.
117 - I've used floats rather than doubles to store relative distances in some
118   places (internal only) where it would save significant amounts of memory.
119   The SVG spec allows you to do this as long as intermediate calculations
120   are done double. Very very long lines might not finish precisely where
121   you want, but that's to be expected with any typesetting. Also,
122   SVGLength only uses floats.
123 - If you look at the six arrays for holding the output data you'll realise
124   that there's no O(1) way to drill down from a paragraph to find its
125   starting glyph. This was a conscious decision to reduce complexity and
126   to save memory. Drilling down isn't actually that slow because a binary
127   chop will work nicely. Add this to the realisation that most of the
128   times you do this will be in response to user actions and hence you only
129   need to be faster than the user and I think the design makes sense.
130 - There are a massive number of functions acting on Layout::iterator. A
131   large number are trivial and will be inline, but is it really necessary
132   to have all these, especially when some can be implemented by the caller
133   using the others?
134 - The separation of methods between Layout and Layout::iterator is a
135   bit arbitrary, because many methods could go in either. I've used the STL
136   model where the iterator itself can only move around; the base class is
137   required to do anything interesting.
138 - I use Pango internally, not Pangomm. The reason for this is lots of
139   Pangomm methods take Glib::ustrings as input and then output byte offsets
140   within the strings. There's simply no way to use byte offsets with
141   ustrings without some very entertaining reinterpret_cast<>s. The Pangomm
142   docs seem to be lacking quite a lot of things mentioned in the Pango
143   docs, too.
144 */
145 class Layout {
146 public:
147     class iterator;
148     friend class iterator;
149     class Calculator;
150     friend class Calculator;
151     class ScanlineMaker;
152     class InfiniteScanlineMaker;
153     class ShapeScanlineMaker;
155     Layout();
156     virtual ~Layout();
158     /** Used to specify any particular text direction required. Used for
159     both the 'direction' and 'block-progression' CSS attributes. */
160     enum Direction {LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP};
162     /** Display alignment for shapes. See appendWrapShape(). */
163     enum DisplayAlign {DISPLAY_ALIGN_BEFORE, DISPLAY_ALIGN_CENTER, DISPLAY_ALIGN_AFTER};
165     /** The optional attributes which can be applied to a SVG text or
166     related tag. See appendText(). See SVG1.1 section 10.4 for the
167     definitions of all these members. See sp_svg_length_list_read() for
168     the standard way to make these vectors. It is the responsibility of
169     the caller to deal with the inheritance of these values using its
170     knowledge of the parse tree. */
171     struct OptionalTextTagAttrs {
172         std::vector<SVGLength> x;
173         std::vector<SVGLength> y;
174         std::vector<SVGLength> dx;
175         std::vector<SVGLength> dy;
176         std::vector<SVGLength> rotate;
177     };
179     /** Control codes which can be embedded in the text to be flowed. See
180     appendControlCode(). */
181     enum TextControlCode {
182         PARAGRAPH_BREAK,    /// forces the flow to move on to the next line
183         SHAPE_BREAK,        /// forces the flow to ignore the remainder of the current shape (from #flow_inside_shapes) and continue at the top of the one after.
184         ARBITRARY_GAP       /// inserts an arbitrarily-sized hole in the flow in line with the current text.
185     };
187     /** For expressing paragraph alignment. These values are rotated in the
188     case of vertical text, but are not dependent on whether the paragraph is
189     rtl or ltr, thus LEFT is always either left or top. */
190     enum Alignment {LEFT, CENTER, RIGHT, FULL};
192     /** The CSS spec allows line-height:normal to be whatever the user agent
193     thinks will look good. This is our value, as a multiple of font-size. */
194     static const double LINE_HEIGHT_NORMAL;
196     // ************************** describing the stuff to flow *************************
198     /** \name Input
199       Methods for describing the text you want to flow, its style, and the
200       shapes to flow in to.
201     */
202     //@{
204     /** Empties everything stored in this class and resets it to its
205     original state, like when it was created. All iterators on this
206     object will be invalidated (but can be revalidated using
207     validateIterator(). */
208     void clear();
210     /** Queries whether any calls have been made to appendText() or
211     appendControlCode() since the object was last cleared. */
212     bool inputExists() const
213         {return !_input_stream.empty();}
215     bool _input_truncated;
216     bool inputTruncated() const
217         {return _input_truncated;}
219     /** adds a new piece of text to the end of the current list of text to
220     be processed. This method can only add text of a consistent style.
221     To add lots of different styles, call it lots of times.
222      \param text  The text. \b Note: only a \em pointer is stored. Do not
223                   mess with the text until after you have called
224                   calculateFlow().
225      \param style The font style. Layout will hold a reference to this
226                   object for the duration of its ownership, ie until you
227                   call clear() or the class is destroyed. Must not be NULL.
228      \param source_cookie  This pointer is treated as opaque by Layout
229                   but will be passed through the flowing process intact so
230                   that callers can use it to refer to the original object
231                   that generated a particular glyph. See Layout::iterator.
232                   Implementation detail: currently all callers put an
233                   SPString in here.
234      \param optional_attributes  A structure containing additional options
235                   for this text. See OptionalTextTagAttrs. The values are
236                   copied to internal storage before this method returns.
237      \param optional_attributes_offset  It is convenient for callers to be
238                   able to use the same \a optional_attributes structure for
239                   several sequential text fields, in which case the vectors
240                   will need to be offset. This parameter causes the <i>n</i>th
241                   element of all the vectors to be read as if it were the
242                   first.
243      \param text_begin  Used for selecting only a substring of \a text
244                   to process.
245      \param text_end    Used for selecting only a substring of \a text
246                   to process.
247     */
248     void appendText(Glib::ustring const &text, SPStyle *style, void *source_cookie, OptionalTextTagAttrs const *optional_attributes, unsigned optional_attributes_offset, Glib::ustring::const_iterator text_begin, Glib::ustring::const_iterator text_end);
249     inline void appendText(Glib::ustring const &text, SPStyle *style, void *source_cookie, OptionalTextTagAttrs const *optional_attributes = NULL, unsigned optional_attributes_offset = 0)
250         {appendText(text, style, source_cookie, optional_attributes, optional_attributes_offset, text.begin(), text.end());}
252     /** Control codes are metadata in the text stream to signify items
253     that occupy real space (unlike style changes) but don't belong in the
254     text string. See TextControlCode for the types available.
256     A control code \em cannot be the first item in the input stream. Use
257     appendText() with an empty string to set up the paragraph properties.
258      \param code    A member of the TextFlowControlCode enumeration.
259      \param width   The width in pixels that this item occupies.
260      \param ascent  The number of pixels above the text baseline that this
261                     control code occupies.
262      \param descent The number of pixels below the text baseline that this
263                     control code occupies.
264      \param source_cookie This pointer is treated as opaque by Layout
265                   but will be passed through the flowing process intact so
266                   that callers can use it to refer to the original object
267                   that generated a particular area. See Layout::iterator.
268                   Implementation detail: currently all callers put an
269                   SPObject in here.
270     Note that for some control codes (eg tab) the values of the \a width,
271     \a ascender and \a descender are implied by the surrounding text (and
272     in the case of tabs, the values set in tab_stops) so the values you pass
273     here are ignored.
274     */
275     void appendControlCode(TextControlCode code, void *source_cookie, double width = 0.0, double ascent = 0.0, double descent = 0.0);
277     /** Stores another shape inside which to flow the text. If this method
278     is never called then no automatic wrapping is done and lines will
279     continue to infinity if necessary. Text can be flowed inside multiple
280     shapes in sequence, like with frames in a DTP package. If the text flows
281     past the end of the last shape all remaining text is ignored.
283       \param shape  The Shape to use next in the flow. The storage for this
284                     is managed by the caller, and need only be valid for
285                     the duration of the call to calculateFlow().
286       \param display_align   The vertical alignment of the text within this
287                     shape. See XSL1.0 section 7.13.4. The behaviour of
288                     settings other than DISPLAY_ALIGN_BEFORE when using
289                     non-rectangular shapes is undefined.
290     */
291     void appendWrapShape(Shape const *shape, DisplayAlign display_align = DISPLAY_ALIGN_BEFORE);
293     //@}
295     // ************************** doing the actual flowing *************************
297     /** \name Processing
298       The method to do the actual work of converting text into glyphs.
299     */
300     //@{
302     /** Takes all the stuff you set with the members above here and creates
303     a load of glyphs for use with the members below here. All iterators on
304     this object will be invalidated (but can be fixed with validateIterator().
305     The implementation just creates a new Layout::Calculator and calls its
306     Calculator::Calculate() method, so if you want more details on the
307     internals, go there.
308       \return  false on failure.
309     */
310     bool calculateFlow();
312     //@}
314     // ************************** operating on the output glyphs *************************
316     /** \name Output
317       Methods for reading and interpreting the output glyphs. See also
318       Layout::iterator.
319     */
320     //@{
322     /** Returns true if there are some glyphs in this object, ie whether
323     computeFlow() has been called on a non-empty input since the object was
324     created or the last call to clear(). */
325     inline bool outputExists() const
326         {return !_characters.empty();}
328     /** Adds all the output glyphs to \a in_arena using the given \a paintbox.
329      \param in_arena  The arena to add the glyphs group to
330      \param paintbox  The current rendering tile
331     */
332     void show(NRArenaGroup *in_arena, NRRect const *paintbox) const;
334     /** Calculates the smallest rectangle completely enclosing all the
335     glyphs.
336       \param bounding_box  Where to store the box
337       \param transform     The transform to be applied to the entire object
338                            prior to calculating its bounds.
339     */
340     void getBoundingBox(NRRect *bounding_box, Geom::Matrix const &transform, int start = -1, int length = -1) const;
342     /** Sends all the glyphs to the given print context.
343      \param ctx   I have
344      \param pbox  no idea
345      \param dbox  what these
346      \param bbox  parameters
347      \param ctm   do yet
348     */
349     void print(SPPrintContext *ctx, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox, Geom::Matrix const &ctm) const;
351 #ifdef HAVE_CAIRO_PDF    
352     /** Renders all the glyphs to the given Cairo rendering context.
353      \param ctx   The Cairo rendering context to be used
354      */
355     void showGlyphs(CairoRenderContext *ctx) const;
356 #endif
358     /** debug and unit test method. Creates a textual representation of the
359     contents of this object. The output is designed to be both human-readable
360     and comprehensible when diffed with a known-good dump. */
361     Glib::ustring dumpAsText() const;
363     /** Moves all the glyphs in the structure so that the baseline of all
364     the characters sits neatly along the path specified. If the text has
365     more than one line the results are undefined. The 'align' means to
366     use the SVG align method as documented in SVG1.1 section 10.13.2.
367     NB: njh has suggested that it would be cool if we could flow from
368     shape to path and back again. This is possible, so this method will be
369     removed at some point.
370     A pointer to \a path is retained by the class for use by the cursor
371     positioning functions. */
372     void fitToPathAlign(SVGLength const &startOffset, Path const &path);
374     /** Convert the specified range of characters into their bezier 
375     outlines.
376     */
377     SPCurve* convertToCurves(iterator const &from_glyph, iterator const &to_glyph) const;
378     inline SPCurve* convertToCurves() const;
380     /** Apply the given transform to all the output presently stored in
381     this object. This only transforms the glyph positions, The glyphs
382     themselves will not be transformed. */
383     void transform(Geom::Matrix const &transform);
385     //@}
387     // **********
389     /** \name Output (Iterators)
390       Methods for operating with the Layout::iterator class. The method
391       names ending with 'Index' return 0-based offsets of the number of
392       items since the beginning of the flow.
393     */
394     //@{
396     /** Returns an iterator pointing at the first glyph of the flowed output.
397     The first glyph is also the first character, line, paragraph, etc. */
398     inline iterator begin() const;
400     /** Returns an iterator pointing just past the end of the last glyph,
401     which is also just past the end of the last chunk, span, etc, etc. */
402     inline iterator end() const;
404     /** Returns an iterator pointing at the given character index. This
405     index should be related to the result from a prior call to
406     iteratorToCharIndex(). */
407     inline iterator charIndexToIterator(int char_index) const;
409     /** Returns the character index from the start of the flow represented
410     by the given iterator. This number isn't very useful, except for when
411     editing text it will stay valid across calls to computeFlow() and will
412     change in predictable ways when characters are added and removed. It's
413     also useful when transitioning old code. */
414     inline int iteratorToCharIndex(iterator const &it) const;
416     /** Checks the validity of the given iterator over the current layout.
417     If it points to a position out of the bounds for this layout it will
418     be corrected to the nearest valid position. If you pass an iterator
419     belonging to a different layout it will be converted to one for this
420     layout. */
421     inline void validateIterator(iterator *it) const;
423     /** Returns an iterator pointing to the cursor position for a mouse
424     click at the given coordinates. */
425     iterator getNearestCursorPositionTo(double x, double y) const;
426     inline iterator getNearestCursorPositionTo(Geom::Point const &point) const;
428     /** Returns an iterator pointing to the letter whose bounding box contains
429     the given coordinates. end() if the point is not over any letter. The
430     iterator will \em not point at the specific glyph within the character. */
431     iterator getLetterAt(double x, double y) const;
432     inline iterator getLetterAt(Geom::Point &point) const;
434     /** Returns an iterator pointing to the character in the output which
435     was created from the given input. If the character at the given byte
436     offset was removed (soft hyphens, for example) the next character after
437     it is returned. If no input was added with the given cookie, end() is
438     returned. If more than one input has the same cookie, the first will
439     be used regardless of the value of \a text_iterator. If
440     \a text_iterator is out of bounds, the first or last character belonging
441     to the given input will be returned accordingly. */
442     iterator sourceToIterator(void *source_cookie, Glib::ustring::const_iterator text_iterator) const;
444     /** Returns an iterator pointing to the first character in the output
445     which was created from the given source. If \a source_cookie is invalid,
446     end() is returned. If more than one input has the same cookie, the
447     first one will be used. */
448     iterator sourceToIterator(void *source_cookie) const;
450     // many functions acting on iterators, most of which are obvious
451     // also most of them don't check that \a it != end(). Be careful.
453     /** Returns the bounding box of the given glyph, and its rotation.
454     The centre of rotation is the horizontal centre of the box at the
455     text baseline. */
456     Geom::OptRect glyphBoundingBox(iterator const &it, double *rotation) const;
458     /** Returns the zero-based line number of the character pointed to by
459     \a it. */
460     inline unsigned lineIndex(iterator const &it) const;
462     /** Returns the zero-based number of the shape which contains the
463     character pointed to by \a it. */
464     inline unsigned shapeIndex(iterator const &it) const;
466     /** Returns true if the character at \a it is a whitespace, as defined
467     by Pango. This is not meant to be used for picking out words from the
468     output, use iterator::nextStartOfWord() and friends instead. */
469     inline bool isWhitespace(iterator const &it) const;
471     /** Returns the unicode character code of the character pointed to by
472     \a it. If \a it == end() the result is undefined. */
473     inline int characterAt(iterator const &it) const;
475     /** Discovers where the character pointed to by \a it came from, by
476     retrieving the cookie that was passed to the call to appendText() or
477     appendControlCode() which generated that output. If \a it == end()
478     then NULL is returned as the cookie. If the character was generated
479     from a call to appendText() then the optional \a text_iterator
480     parameter is set to point to the actual character, otherwise
481     \a text_iterator is unaltered. */
482     void getSourceOfCharacter(iterator const &it, void **source_cookie, Glib::ustring::iterator *text_iterator = NULL) const;
484     /** For latin text, the left side of the character, on the baseline */
485     Geom::Point characterAnchorPoint(iterator const &it) const;
487     /** For left aligned text, the leftmost end of the baseline
488     For rightmost text, the rightmost... you probably got it by now ;-)*/
489     boost::optional<Geom::Point> baselineAnchorPoint() const;
491     /** This is that value to apply to the x,y attributes of tspan role=line
492     elements, and hence it takes alignment into account. */
493     Geom::Point chunkAnchorPoint(iterator const &it) const;
495     /** Returns the box extents (not ink extents) of the given character.
496     The centre of rotation is at the horizontal centre of the box on the
497     text baseline. */
498     Geom::Rect characterBoundingBox(iterator const &it, double *rotation = NULL) const;
500     /** Basically uses characterBoundingBox() on all the characters from
501     \a start to \a end and returns the union of these boxes. The return value
502     is a list of zero or more quadrilaterals specified by a group of four
503     points for each, thus size() is always a multiple of four. */
504     std::vector<Geom::Point> createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Matrix const &transform) const;
506     /** Returns true if \a it points to a character which is a valid cursor
507     position, as defined by Pango. */
508     inline bool isCursorPosition(iterator const &it) const;
510     /** Gets the ideal cursor shape for a given iterator. The result is
511     undefined if \a it is not at a valid cursor position.
512       \param it        The location in the output
513       \param position  The pixel location of the centre of the 'bottom' of
514                        the cursor.
515       \param height    The height in pixels of the surrounding text
516       \param rotation  The angle to draw from \a position. Radians, zero up,
517                        increasing clockwise.
518     */
519     void queryCursorShape(iterator const &it, Geom::Point &position, double &height, double &rotation) const;
521     /** Returns true if \a it points to a character which is a the start of
522     a word, as defined by Pango. */
523     inline bool isStartOfWord(iterator const &it) const;
525     /** Returns true if \a it points to a character which is a the end of
526     a word, as defined by Pango. */
527     inline bool isEndOfWord(iterator const &it) const;
529     /** Returns true if \a it points to a character which is a the start of
530     a sentence, as defined by Pango. */
531     inline bool isStartOfSentence(iterator const &it) const;
533     /** Returns true if \a it points to a character which is a the end of
534     a sentence, as defined by Pango. */
535     inline bool isEndOfSentence(iterator const &it) const;
537     /** Returns the zero-based number of the paragraph containing the
538     character pointed to by \a it. */
539     inline unsigned paragraphIndex(iterator const &it) const;
541     /** Returns the actual alignment used for the paragraph containing
542     the character pointed to by \a it. This means that the CSS 'start'
543     and 'end' are correctly translated into LEFT or RIGHT according to
544     the paragraph's directionality. For vertical text, LEFT is top
545     alignment and RIGHT is bottom. */
546     inline Alignment paragraphAlignment(iterator const &it) const;
548     /** Returns kerning information which could cause the current output
549     to be exactly reproduced if the letter and word spacings were zero and
550     full justification was not used. The x and y arrays are not used, but
551     they are cleared. The dx applied to the first character in a chunk
552     will always be zero. If the region between \a from and \a to crosses
553     a line break then the results may be surprising, and are undefined.
554     Trailing zeros on the returned arrays will be trimmed. */
555     void simulateLayoutUsingKerning(iterator const &from, iterator const &to, OptionalTextTagAttrs *result) const;
557     //@}
559     /// it's useful for this to be public so that ScanlineMaker can use it
560     struct LineHeight {
561         double ascent;
562         double descent;
563         double leading;
564         inline double total() const {return ascent + descent + leading;}
565         inline void setZero() {ascent = descent = leading = 0.0;}
566         inline LineHeight& operator*=(double x) {ascent *= x; descent *= x; leading *= x; return *this;}
567         void max(LineHeight const &other);   /// makes this object contain the largest of all three members between this object and other
568     };
570     /// see _enum_converter()
571     struct EnumConversionItem {
572         int input, output;
573     };
575 private:
576     /** Erases all the stuff set by the owner as input, ie #_input_stream
577     and #_input_wrap_shapes. */
578     void _clearInputObjects();
580     /** Erases all the stuff output by computeFlow(). Glyphs and things. */
581     void _clearOutputObjects();
583     static const gunichar UNICODE_SOFT_HYPHEN;
585     // ******************* input flow
587     enum InputStreamItemType {TEXT_SOURCE, CONTROL_CODE};
589     class InputStreamItem {
590     public:
591         virtual ~InputStreamItem() {}
592         virtual InputStreamItemType Type() =0;
593         void *source_cookie;
594     };
596     /** Represents a text item in the input stream. See #_input_stream.
597     Most of the members are copies of the values passed to appendText(). */
598     class InputStreamTextSource : public InputStreamItem {
599     public:
600         virtual InputStreamItemType Type() {return TEXT_SOURCE;}
601         virtual ~InputStreamTextSource();
602         Glib::ustring const *text;    /// owned by the caller
603         Glib::ustring::const_iterator text_begin, text_end;
604         int text_length;    /// in characters, from text_start to text_end only
605         SPStyle *style;
606         /** These vectors can (often will) be shorter than the text
607         in this source, but never longer. */
608         std::vector<SVGLength> x;
609         std::vector<SVGLength> y;
610         std::vector<SVGLength> dx;
611         std::vector<SVGLength> dy;
612         std::vector<SVGLength> rotate;
613         
614         // a few functions for some of the more complicated style accesses
615         float styleComputeFontSize() const;
616         /// The return value must be freed with pango_font_description_free()
617         PangoFontDescription *styleGetFontDescription() const;
618         font_instance *styleGetFontInstance() const;
619         Direction styleGetBlockProgression() const;
620         Alignment styleGetAlignment(Direction para_direction, bool try_text_align) const;
621     };
623     /** Represents a control code item in the input stream. See
624     #_input_streams. All the members are copies of the values passed to
625     appendControlCode(). */
626     class InputStreamControlCode : public InputStreamItem {
627     public:
628         virtual InputStreamItemType Type() {return CONTROL_CODE;}
629         TextControlCode code;
630         double ascent;
631         double descent;
632         double width;
633     };
635     /** This is our internal storage for all the stuff passed to the
636     appendText() and appendControlCode() functions. */
637     std::vector<InputStreamItem*> _input_stream;
639     /** The parameters to appendText() are allowed to be a little bit
640     complex. This copies them to be the right length and starting at zero.
641     We also don't want to write five bits of identical code just with
642     different variable names. */
643     static void _copyInputVector(std::vector<SVGLength> const &input_vector, unsigned input_offset, std::vector<SVGLength> *output_vector, size_t max_length);
645     /** There are a few cases where we have different sets of enums meaning
646     the same thing, eg Pango font styles vs. SPStyle font styles. These need
647     converting. */
648     static int _enum_converter(int input, EnumConversionItem const *conversion_table, unsigned conversion_table_size);
650     /** The overall block-progression of the whole flow. */
651     inline Direction _blockProgression() const
652         {return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetBlockProgression();}
654     /** so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM */
655     static bool _directions_are_orthogonal(Direction d1, Direction d2);
657     /** If the output is empty callers still want to be able to call
658     queryCursorShape() and get a valid answer so, while #_input_wrap_shapes
659     can still be considered valid, we need to precompute the cursor shape
660     for this case. */
661     void _calculateCursorShapeForEmpty();
663     struct CursorShape {
664         Geom::Point position;
665         double height;
666         double rotation;
667     } _empty_cursor_shape;
669     // ******************* input shapes
671     struct InputWrapShape {
672         Shape const *shape;        /// as passed to Layout::appendWrapShape()
673         DisplayAlign display_align;   /// as passed to Layout::appendWrapShape()
674     };
675     std::vector<InputWrapShape> _input_wrap_shapes;
677     // ******************* output
679     /** as passed to fitToPathAlign() */
680     Path const *_path_fitted;
682     struct Glyph;
683     struct Character;
684     struct Span;
685     struct Chunk;
686     struct Line;
687     struct Paragraph;
689     struct Glyph {
690         int glyph;
691         unsigned in_character;
692         float x;         /// relative to the start of the chunk
693         float y;         /// relative to the current line's baseline
694         float rotation;  /// absolute, modulo any object transforms, which we don't know about
695         float width;
696         inline Span const & span(Layout const *l) const {return l->_spans[l->_characters[in_character].in_span];}
697         inline Chunk const & chunk(Layout const *l) const {return l->_chunks[l->_spans[l->_characters[in_character].in_span].in_chunk];}
698         inline Line const & line(Layout const *l) const {return l->_lines[l->_chunks[l->_spans[l->_characters[in_character].in_span].in_chunk].in_line];}
699     };
700     struct Character {
701         unsigned in_span;
702         float x;      /// relative to the start of the *span* (so we can do block-progression)
703         PangoLogAttr char_attributes;
704         int in_glyph;   /// will be -1 if this character has no visual representation
705         inline Span const & span(Layout const *l) const {return l->_spans[in_span];}
706         inline Chunk const & chunk(Layout const *l) const {return l->_chunks[l->_spans[in_span].in_chunk];}
707         inline Line const & line(Layout const *l) const {return l->_lines[l->_chunks[l->_spans[in_span].in_chunk].in_line];}
708         inline Paragraph const & paragraph(Layout const *l) const {return l->_paragraphs[l->_lines[l->_chunks[l->_spans[in_span].in_chunk].in_line].in_paragraph];}
709         // to get the advance width of a character, subtract the x values if it's in the middle of a span, or use span.x_end if it's at the end
710     };
711     struct Span {
712         unsigned in_chunk;
713         font_instance *font;
714         float font_size;
715         float x_start;   /// relative to the start of the chunk
716         float x_end;     /// relative to the start of the chunk
717         LineHeight line_height;
718         double baseline_shift;  /// relative to the line's baseline
719         Direction direction;     /// See CSS3 section 3.2. Either rtl or ltr
720         Direction block_progression;  /// See CSS3 section 3.2. The direction in which lines go.
721         unsigned in_input_stream_item;
722         Glib::ustring::const_iterator input_stream_first_character;
723         inline Chunk const & chunk(Layout const *l) const {return l->_chunks[in_chunk];}
724         inline Line const & line(Layout const *l) const {return l->_lines[l->_chunks[in_chunk].in_line];}
725         inline Paragraph const & paragraph(Layout const *l) const {return l->_paragraphs[l->_lines[l->_chunks[in_chunk].in_line].in_paragraph];}
726     };
727     struct Chunk {
728         unsigned in_line;
729         double left_x;
730     };
731     struct Line {
732         unsigned in_paragraph;
733         double baseline_y;
734         unsigned in_shape;
735     };
736     struct Paragraph {
737         Direction base_direction;    /// can be overridden by child Span objects
738         Alignment alignment;
739     };
740     std::vector<Paragraph> _paragraphs;
741     std::vector<Line> _lines;
742     std::vector<Chunk> _chunks;
743     std::vector<Span> _spans;
744     std::vector<Character> _characters;
745     std::vector<Glyph> _glyphs;
747     /** gets the overall matrix that transforms the given glyph from local
748     space to world space. */
749     void _getGlyphTransformMatrix(int glyph_index, Geom::Matrix *matrix) const;
751     // loads of functions to drill down the object tree, all of them
752     // annoyingly similar and all of them requiring predicate functors.
753     // I'll be buggered if I can find a way to make it work with
754     // functions or with a templated functor, so macros it is.
755 #define EMIT_PREDICATE(name, object_type, index_generator)                  \
756     class name {                                                            \
757         Layout const * const _flow;                                         \
758     public:                                                                 \
759         inline name(Layout const *flow) : _flow(flow) {}                    \
760         inline bool operator()(object_type const &object, unsigned index)   \
761             {return index_generator < index;}                               \
762     }
763 // end of macro
764     EMIT_PREDICATE(PredicateLineToSpan,        Span,      _flow->_chunks[object.in_chunk].in_line);
765     EMIT_PREDICATE(PredicateLineToCharacter,   Character, _flow->_chunks[_flow->_spans[object.in_span].in_chunk].in_line);
766     EMIT_PREDICATE(PredicateSpanToCharacter,   Character, object.in_span);
767     EMIT_PREDICATE(PredicateSourceToCharacter, Character, _flow->_spans[object.in_span].in_input_stream_item);
769     inline unsigned _lineToSpan(unsigned line_index) const
770         {return std::lower_bound(_spans.begin(), _spans.end(), line_index, PredicateLineToSpan(this)) - _spans.begin();}
771     inline unsigned _lineToCharacter(unsigned line_index) const
772         {return std::lower_bound(_characters.begin(), _characters.end(), line_index, PredicateLineToCharacter(this)) - _characters.begin();}
773     inline unsigned _spanToCharacter(unsigned span_index) const
774         {return std::lower_bound(_characters.begin(), _characters.end(), span_index, PredicateSpanToCharacter(this)) - _characters.begin();}
775     inline unsigned _sourceToCharacter(unsigned source_index) const
776         {return std::lower_bound(_characters.begin(), _characters.end(), source_index, PredicateSourceToCharacter(this)) - _characters.begin();}
778     /** given an x coordinate and a line number, returns an iterator
779     pointing to the closest cursor position on that line to the
780     coordinate. */
781     iterator _cursorXOnLineToIterator(unsigned line_index, double local_x) const;
783     /** calculates the width of a chunk, which is the largest x
784     coordinate (start or end) of the spans contained within it. */
785     double _getChunkWidth(unsigned chunk_index) const;
786 };
788 /** \brief Holds a position within the glyph output of Layout.
790 Used to access the output of a Layout, query information and generally
791 move around in it. See Layout for a glossary of the names of functions.
793 I'm not going to document all the methods because most of their names make
794 their function self-evident.
796 A lot of the functions would do the same thing in a naive implementation
797 for latin-only text, for example nextCharacter(), nextCursorPosition() and
798 cursorRight(). Generally it's fairly obvious which one you should use in a
799 given situation, but sometimes you might need to put some thought in to it.
801 All the methods return false if the requested action would have caused the
802 current position to move out of bounds. In this case the position is moved
803 to either begin() or end(), depending on which direction you were going.
805 Note that some characters do not have a glyph representation (eg line
806 breaks), so if you try using prev/nextGlyph() from one of these you're
807 heading for a crash.
808 */
809 class Layout::iterator {
810 public:
811     friend class Layout;
812     // this is just so you can create uninitialised iterators - don't actually try to use one
813     iterator() : _parent_layout(NULL) {}
814     // no copy constructor required, the default does what we want
815     bool operator== (iterator const &other) const
816         {return _glyph_index == other._glyph_index && _char_index == other._char_index;}
817     bool operator!= (iterator const &other) const
818         {return _glyph_index != other._glyph_index || _char_index != other._char_index;}
820     /* mustn't compare _glyph_index in these operators because for characters
821     that don't have glyphs (line breaks, elided soft hyphens, etc), the glyph
822     index is -1 which makes them not well-ordered. To be honest, interating by
823     glyphs is not very useful and should be avoided. */
824     bool operator< (iterator const &other) const
825         {return _char_index < other._char_index;}
826     bool operator<= (iterator const &other) const
827         {return _char_index <= other._char_index;}
828     bool operator> (iterator const &other) const
829         {return _char_index > other._char_index;}
830     bool operator>= (iterator const &other) const
831         {return _char_index >= other._char_index;}
833     /* **** visual-oriented methods **** */
835     //glyphs
836     inline bool prevGlyph();
837     inline bool nextGlyph();
839     //span
840     bool prevStartOfSpan();
841     bool thisStartOfSpan();
842     bool nextStartOfSpan();
844     //chunk
845     bool prevStartOfChunk();
846     bool thisStartOfChunk();
847     bool nextStartOfChunk();
849     //line
850     bool prevStartOfLine();
851     bool thisStartOfLine();
852     bool nextStartOfLine();
853     bool thisEndOfLine();
855     //shape
856     bool prevStartOfShape();
857     bool thisStartOfShape();
858     bool nextStartOfShape();
860     /* **** text-oriented methods **** */
862     //characters
863     inline bool nextCharacter();
864     inline bool prevCharacter();
866     bool nextCursorPosition();
867     bool prevCursorPosition();
868     bool nextLineCursor(int n = 1);
869     bool prevLineCursor(int n = 1);
871     //words
872     bool nextStartOfWord();
873     bool prevStartOfWord();
874     bool nextEndOfWord();
875     bool prevEndOfWord();
877     //sentences
878     bool nextStartOfSentence();
879     bool prevStartOfSentence();
880     bool nextEndOfSentence();
881     bool prevEndOfSentence();
883     //paragraphs
884     bool prevStartOfParagraph();
885     bool thisStartOfParagraph();
886     bool nextStartOfParagraph();
887     //no endOfPara methods because that's just the previous char
889     //sources
890     bool prevStartOfSource();
891     bool thisStartOfSource();
892     bool nextStartOfSource();
894     //logical cursor movement
895     bool cursorUp(int n = 1);
896     bool cursorDown(int n = 1);
897     bool cursorLeft();
898     bool cursorRight();
900     //logical cursor movement (by word or paragraph)
901     bool cursorUpWithControl();
902     bool cursorDownWithControl();
903     bool cursorLeftWithControl();
904     bool cursorRightWithControl();
906 private:
907     Layout const *_parent_layout;
908     int _glyph_index;      /// index into Layout::glyphs, or -1
909     unsigned _char_index;       /// index into Layout::character
910     bool _cursor_moving_vertically;
911     /** for cursor up/down movement we must maintain the x position where
912     we started so the cursor doesn't 'drift' left or right with the repeated
913     quantization to character boundaries. */
914     double _x_coordinate;
916     inline iterator(Layout const *p, unsigned c, int g)
917         : _parent_layout(p), _glyph_index(g), _char_index(c), _cursor_moving_vertically(false), _x_coordinate(0.0) {}
918     inline iterator(Layout const *p, unsigned c)
919         : _parent_layout(p), _glyph_index(p->_characters[c].in_glyph), _char_index(c), _cursor_moving_vertically(false), _x_coordinate(0.0) {}
920     // no dtor required
921     void beginCursorUpDown();  /// stores the current x coordinate so that the cursor won't drift. See #_x_coordinate
923     /** moves forward or backwards one cursor position according to the
924     directionality of the current paragraph, but ignoring block progression.
925     Helper for the cursor*() functions. */
926     bool _cursorLeftOrRightLocalX(Direction direction);
928     /** moves forward or backwards by until the next character with
929     is_word_start according to the directionality of the current paragraph,
930     but ignoring block progression. Helper for the cursor*WithControl()
931     functions. */
932     bool _cursorLeftOrRightLocalXByWord(Direction direction);
933 };
935 // ************************** inline methods
937 inline SPCurve* Layout::convertToCurves() const
938     {return convertToCurves(begin(), end());}
940 inline Layout::iterator Layout::begin() const
941     {return iterator(this, 0, 0);}
943 inline Layout::iterator Layout::end() const
944     {return iterator(this, _characters.size(), _glyphs.size());}
946 inline Layout::iterator Layout::charIndexToIterator(int char_index) const
948     if (char_index < 0) return begin();
949     if (char_index >= (int)_characters.size()) return end();
950     return iterator(this, char_index);
953 inline int Layout::iteratorToCharIndex(Layout::iterator const &it) const
954     {return it._char_index;}
956 inline void Layout::validateIterator(Layout::iterator *it) const
958     it->_parent_layout = this;
959     if (it->_char_index >= _characters.size()) {
960         it->_char_index = _characters.size();
961         it->_glyph_index = _glyphs.size();
962     } else
963         it->_glyph_index = _characters[it->_char_index].in_glyph;
966 inline Layout::iterator Layout::getNearestCursorPositionTo(Geom::Point const &point) const
967     {return getNearestCursorPositionTo(point[0], point[1]);}
969 inline Layout::iterator Layout::getLetterAt(Geom::Point &point) const
970     {return getLetterAt(point[0], point[1]);}
972 inline unsigned Layout::lineIndex(iterator const &it) const
973     {return it._char_index == _characters.size() ? _lines.size() - 1 : _characters[it._char_index].chunk(this).in_line;}
975 inline unsigned Layout::shapeIndex(iterator const &it) const
976     {return it._char_index == _characters.size() ? _input_wrap_shapes.size() - 1 : _characters[it._char_index].line(this).in_shape;}
978 inline bool Layout::isWhitespace(iterator const &it) const
979     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_white;}
981 inline int Layout::characterAt(iterator const &it) const
983     void *unused;
984     Glib::ustring::iterator text_iter;
985     getSourceOfCharacter(it, &unused, &text_iter);
986     return *text_iter;
989 inline bool Layout::isCursorPosition(iterator const &it) const
990     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_cursor_position;}
992 inline bool Layout::isStartOfWord(iterator const &it) const
993     {return it._char_index != _characters.size() && _characters[it._char_index].char_attributes.is_word_start;}
995 inline bool Layout::isEndOfWord(iterator const &it) const
996     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_word_end;}
998 inline bool Layout::isStartOfSentence(iterator const &it) const
999     {return it._char_index != _characters.size() && _characters[it._char_index].char_attributes.is_sentence_start;}
1001 inline bool Layout::isEndOfSentence(iterator const &it) const
1002     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_sentence_end;}
1004 inline unsigned Layout::paragraphIndex(iterator const &it) const
1005     {return it._char_index == _characters.size() ? _paragraphs.size() - 1 : _characters[it._char_index].line(this).in_paragraph;}
1007 inline Layout::Alignment Layout::paragraphAlignment(iterator const &it) const
1008     {return _paragraphs[paragraphIndex(it)].alignment;}
1010 inline bool Layout::iterator::nextGlyph()
1012     _cursor_moving_vertically = false;
1013     if (_glyph_index >= (int)_parent_layout->_glyphs.size() - 1) {
1014         if (_glyph_index == (int)_parent_layout->_glyphs.size()) return false;
1015         _char_index = _parent_layout->_characters.size();
1016         _glyph_index = _parent_layout->_glyphs.size();
1017     }
1018     else _char_index = _parent_layout->_glyphs[++_glyph_index].in_character;
1019     return true;
1022 inline bool Layout::iterator::prevGlyph()
1024     _cursor_moving_vertically = false;
1025     if (_glyph_index == 0) return false;
1026     _char_index = _parent_layout->_glyphs[--_glyph_index].in_character;
1027     return true;
1030 inline bool Layout::iterator::nextCharacter()
1032     _cursor_moving_vertically = false;
1033     if (_char_index + 1 >= _parent_layout->_characters.size()) {
1034         if (_char_index == _parent_layout->_characters.size()) return false;
1035         _char_index = _parent_layout->_characters.size();
1036         _glyph_index = _parent_layout->_glyphs.size();
1037     }
1038     else _glyph_index = _parent_layout->_characters[++_char_index].in_glyph;
1039     return true;
1042 inline bool Layout::iterator::prevCharacter()
1044     _cursor_moving_vertically = false;
1045     if (_char_index == 0) return false;
1046     _glyph_index = _parent_layout->_characters[--_char_index].in_glyph;
1047     return true;
1050 }//namespace Text
1051 }//namespace Inkscape
1053 #endif
1056 /*
1057   Local Variables:
1058   mode:c++
1059   c-file-style:"stroustrup"
1060   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1061   indent-tabs-mode:nil
1062   fill-column:99
1063   End:
1064 */
1065 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :