Code

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