Code

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