Code

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