1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Inkscape::Text::Layout - text layout engine
4  *
5  * Authors:
6  *   Richard Hughes <cyreve@users.sf.net>
7  *
8  * Copyright (C) 2005 Richard Hughes
9  *
10  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11  */
12 #ifndef __LAYOUT_TNG_H__
13 #define __LAYOUT_TNG_H__
14 
15 //#define DEBUG_TEXTLAYOUT_DUMPASTEXT
16 
17 #include <2geom/d2.h>
18 #include <2geom/affine.h>
19 #include <glibmm/ustring.h>
20 #include <memory>
21 #include <pango/pango-break.h>
22 #include <algorithm>
23 #include <vector>
24 #include <optional>
25 #include <svg/svg-length.h>
26 #include "style-enums.h"
27 
28 namespace Inkscape {
29         namespace Extension {
30                 namespace Internal {
31                         class CairoRenderContext;
32                 }
33         }
34 }
35 
36 using Inkscape::Extension::Internal::CairoRenderContext;
37 
38 class SPStyle;
39 class SPObject;
40 class Shape;
41 struct SPPrintContext;
42 class Path;
43 class SPCurve;
44 class font_instance;
45 typedef struct _PangoFontDescription PangoFontDescription;
46 
47 namespace Inkscape {
48 class DrawingGroup;
49 
50 namespace Text {
51 
52 /** \brief Generates the layout for either wrapped or non-wrapped text and stores the result
53 
54 Use this class for all your text output needs. It takes text with formatting
55 markup as input and turns that into the glyphs and their necessary positions.
56 It stores the glyphs internally, but maintains enough information to both
57 retrieve your own rendering information if you wish and to perform visual
58 text editing where the output refers back to where it came from.
59 
60 Usage:
61 -# Construct
62 -# Set the text using appendText() and appendControlCode()
63 -# If you want text wrapping, call appendWrapShape() a few times
64 -# Call calculateFlow()
65 -# You can go several directions from here, but the most interesting
66    things start with creating a Layout::iterator with begin() or end().
67 
68 Terminology, in descending order of size:
69 - Flow: Not often used, but when it is it means all the text
70 - Shape: A Shape object which is used to represent one of the regions inside
71   which to flow the text. Can overlap with...
72 - Paragraph: Err...A paragraph. Contains one or more...
73 - Line: An entire horizontal line with a common baseline. Contains one or
74   more...
75 - Chunk: You only get more than one of these when a shape is sufficiently
76   complex that the text has to flow either side of some obstruction in
77   the middle. A chunk is the base unit for wrapping. Contains one or more...
78 - Span: A convenient subset of a chunk with the same font, style,
79   directionality, block progression and input stream. Fill and outline
80   need not be constant because that's a later rendering stage.
81 - This is where it gets weird because a span will contain one or more
82   elements of both of the following, which can overlap with each other in
83   any way:
84   - Character: a single Unicode codepoint from an input stream. Many arabic
85     characters contain multiple glyphs
86   - Glyph: a rendering primitive for font engines. A ligature glyph will
87     represent multiple characters.
88 
89 Other terminology:
90 - Input stream: An object representing a single call to appendText() or
91   appendControlCode().
92 - Control code: Metadata in the text stream to signify items that occupy
93   real space (unlike style changes) but don't belong in the text string.
94   Paragraph breaks are in this category. See Layout::TextControlCode.
95 - SVG1.1: The W3C Recommendation "Scalable Vector Graphics (SVG) 1.1"
96   http://www.w3.org/TR/SVG11/
97 - 'left', 'down', etc: These terms are generally used to mean what they
98   mean in left-to-right, top-to-bottom text but rotated or reflected for
99   the current directionality. Thus, the 'width' of a ttb line is actually
100   its height, and the (internally stored) y coordinate of a glyph is
101   actually its x coordinate. Confusing to the reader but much simpler in
102   the code. All public methods use real x and y.
103 
104 Comments:
105 - There's a strong emphasis on international support in this class, but
106   that's primarily because once you can display all the insane things
107   required by various languages, simple things like styling text are
108   almost trivial.
109 - There are a few places (appendText() is one) where pointers are held to
110   caller-owned objects and used for quite a long time. This is messy but
111   is safe for our usage scenario and in many cases the cost of copying the
112   objects is quite high.
113 - "Why isn't foo here?": Ask yourself if it's possible to implement foo
114   externally using iterators. However this may not mean that it doesn't
115   belong as a member, though.
116 - I've used floats rather than doubles to store relative distances in some
117   places (internal only) where it would save significant amounts of memory.
118   The SVG spec allows you to do this as long as intermediate calculations
119   are done double. Very very long lines might not finish precisely where
120   you want, but that's to be expected with any typesetting. Also,
121   SVGLength only uses floats.
122 - If you look at the six arrays for holding the output data you'll realise
123   that there's no O(1) way to drill down from a paragraph to find its
124   starting glyph. This was a conscious decision to reduce complexity and
125   to save memory. Drilling down isn't actually that slow because a binary
126   chop will work nicely. Add this to the realisation that most of the
127   times you do this will be in response to user actions and hence you only
128   need to be faster than the user and I think the design makes sense.
129 - There are a massive number of functions acting on Layout::iterator. A
130   large number are trivial and will be inline, but is it really necessary
131   to have all these, especially when some can be implemented by the caller
132   using the others?
133 - The separation of methods between Layout and Layout::iterator is a
134   bit arbitrary, because many methods could go in either. I've used the STL
135   model where the iterator itself can only move around; the base class is
136   required to do anything interesting.
137 - I use Pango internally, not Pangomm. The reason for this is lots of
138   Pangomm methods take Glib::ustrings as input and then output byte offsets
139   within the strings. There's simply no way to use byte offsets with
140   ustrings without some very entertaining reinterpret_cast<>s. The Pangomm
141   docs seem to be lacking quite a lot of things mentioned in the Pango
142   docs, too.
143 */
144 class Layout {
145 public:
146     class iterator;
147     friend class iterator;
148     class Calculator;
149     friend class Calculator;
150     class ScanlineMaker;
151     class InfiniteScanlineMaker;
152     class ShapeScanlineMaker;
153 
154     Layout();
155     virtual ~Layout();
156 
157     /** Used to specify any particular text direction required. Used for
158     both the 'direction' and 'block-progression' CSS attributes. */
159     enum Direction {LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP};
160 
161     /** Used to specify orientation of glyphs in vertical text. */
162     enum Orientation {ORIENTATION_UPRIGHT, ORIENTATION_SIDEWAYS};
163 
164 
165     /** Display alignment for shapes. See appendWrapShape(). */
166     enum DisplayAlign {DISPLAY_ALIGN_BEFORE, DISPLAY_ALIGN_CENTER, DISPLAY_ALIGN_AFTER};
167 
168     /** lengthAdjust values */
169     enum LengthAdjust {LENGTHADJUST_SPACING, LENGTHADJUST_SPACINGANDGLYPHS};
170 
171     enum WrapMode {
172         WRAP_NONE,         // No wrapping or wrapping via role="line".
173         WRAP_WHITE_SPACE,  // Wrapping via 'white-space' property.
174         WRAP_INLINE_SIZE,  // Wrapping via 'inline-size' property.
175         WRAP_SHAPE_INSIDE  // Wrapping via 'shape-inside' propertry.
176     } wrap_mode = WRAP_NONE;
177 
178     /** The optional attributes which can be applied to a SVG text or
179     related tag. See appendText(). See SVG1.1 section 10.4 for the
180     definitions of all these members. See sp_svg_length_list_read() for
181     the standard way to make these vectors. It is the responsibility of
182     the caller to deal with the inheritance of these values using its
183     knowledge of the parse tree. */
184     struct OptionalTextTagAttrs {
185         std::vector<SVGLength> x;
186         std::vector<SVGLength> y;
187         std::vector<SVGLength> dx;
188         std::vector<SVGLength> dy;
189         std::vector<SVGLength> rotate;
190         SVGLength textLength;
191         LengthAdjust lengthAdjust;
192     };
193 
194     /** Control codes which can be embedded in the text to be flowed. See
195     appendControlCode(). */
196     enum TextControlCode {
197         PARAGRAPH_BREAK,    /// forces the flow to move on to the next line
198         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.
199         ARBITRARY_GAP       /// inserts an arbitrarily-sized hole in the flow in line with the current text.
200     };
201 
202     /** For expressing paragraph alignment. These values are rotated in the
203     case of vertical text, but are not dependent on whether the paragraph is
204     rtl or ltr, thus LEFT is always either left or top. */
205     enum Alignment {LEFT, CENTER, RIGHT, FULL, NONE};
206 
207     /** The CSS spec allows line-height:normal to be whatever the user agent
208     thinks will look good. This is our value, as a multiple of font-size. */
209     static const double LINE_HEIGHT_NORMAL;
210 
211     // ************************** describing the stuff to flow *************************
212 
213     /** \name Input
214       Methods for describing the text you want to flow, its style, and the
215       shapes to flow in to.
216     */
217     //@{
218 
219     /** Empties everything stored in this class and resets it to its
220     original state, like when it was created. All iterators on this
221     object will be invalidated (but can be revalidated using
222     validateIterator(). */
223     void clear();
224 
225     /** Queries whether any calls have been made to appendText() or
226     appendControlCode() since the object was last cleared. */
inputExists()227     bool inputExists() const
228         {return !_input_stream.empty();}
229 
230     bool _input_truncated = false;
inputTruncated()231     bool inputTruncated() const
232         {return _input_truncated;}
233 
234     /** adds a new piece of text to the end of the current list of text to
235     be processed. This method can only add text of a consistent style.
236     To add lots of different styles, call it lots of times.
237      \param text  The text. \b Note: only a \em pointer is stored. Do not
238                   mess with the text until after you have called
239                   calculateFlow().
240      \param style The font style. Layout will hold a reference to this
241                   object for the duration of its ownership, ie until you
242                   call clear() or the class is destroyed. Must not be NULL.
243      \param source  Pointer to object that is source of text.
244      \param optional_attributes  A structure containing additional options
245                   for this text. See OptionalTextTagAttrs. The values are
246                   copied to internal storage before this method returns.
247      \param optional_attributes_offset  It is convenient for callers to be
248                   able to use the same \a optional_attributes structure for
249                   several sequential text fields, in which case the vectors
250                   will need to be offset. This parameter causes the <i>n</i>th
251                   element of all the vectors to be read as if it were the
252                   first.
253      \param text_begin  Used for selecting only a substring of \a text
254                   to process.
255      \param text_end    Used for selecting only a substring of \a text
256                   to process.
257     */
258     void appendText(Glib::ustring const &text, SPStyle *style, SPObject *source, OptionalTextTagAttrs const *optional_attributes, unsigned optional_attributes_offset, Glib::ustring::const_iterator text_begin, Glib::ustring::const_iterator text_end);
259     inline void appendText(Glib::ustring const &text, SPStyle *style, SPObject *source, OptionalTextTagAttrs const *optional_attributes = nullptr, unsigned optional_attributes_offset = 0)
260         {appendText(text, style, source, optional_attributes, optional_attributes_offset, text.begin(), text.end());}
261 
262     /** Control codes are metadata in the text stream to signify items
263     that occupy real space (unlike style changes) but don't belong in the
264     text string. See TextControlCode for the types available.
265 
266     A control code \em cannot be the first item in the input stream. Use
267     appendText() with an empty string to set up the paragraph properties.
268      \param code    A member of the TextFlowControlCode enumeration.
269      \param width   The width in pixels that this item occupies.
270      \param ascent  The number of pixels above the text baseline that this
271                     control code occupies.
272      \param descent The number of pixels below the text baseline that this
273                     control code occupies.
274      \param source  Pointer to object that is source of control code.
275     Note that for some control codes (eg tab) the values of the \a width,
276     \a ascender and \a descender are implied by the surrounding text (and
277     in the case of tabs, the values set in tab_stops) so the values you pass
278     here are ignored.
279     */
280     void appendControlCode(TextControlCode code, SPObject *source, double width = 0.0, double ascent = 0.0, double descent = 0.0);
281 
282     /** Stores another shape inside which to flow the text. If this method
283     is never called then no automatic wrapping is done and lines will
284     continue to infinity if necessary. Text can be flowed inside multiple
285     shapes in sequence, like with frames in a DTP package. If the text flows
286     past the end of the last shape all remaining text is ignored.
287 
288       \param shape  The Shape to use next in the flow. The storage for this
289                     is managed by the caller, and need only be valid for
290                     the duration of the call to calculateFlow().
291       \param display_align   The vertical alignment of the text within this
292                     shape. See XSL1.0 section 7.13.4. The behaviour of
293                     settings other than DISPLAY_ALIGN_BEFORE when using
294                     non-rectangular shapes is undefined.
295     */
296     void appendWrapShape(Shape const *shape, DisplayAlign display_align = DISPLAY_ALIGN_BEFORE);
297 
298     // ************************** textLength and friends *************************
299 
300     /** Gives the length target of this layout, as given by textLength attribute.
301 
302         FIXME: by putting it here we only support @textLength on text and flowRoot, not on any
303         spans inside. For spans, we will need to add markers of start and end of a textLength span
304         into the _input_stream. These spans can nest (SVG 1.1, section 10.5). After a first layout
305         calculation, we would go through the input stream and, for each end of a textLength span,
306         go through its items, choose those where it wasn't yet set by a nested span, calculate
307         their number of characters, divide the length deficit by it, and set set the
308         textLengthMultiplier for those characters only. For now we do this for the entire layout,
309         without dealing with spans.
310     */
311     SVGLength textLength;
312 
313     /** How do we meet textLength if specified: by letterspacing or by scaling horizontally */
314     LengthAdjust lengthAdjust = LENGTHADJUST_SPACING;
315 
316     /** By how much each character needs to be wider or narrower, using the specified lengthAdjust
317         strategy, for the layout to meet its textLength target. Is set to non-zero after the layout
318         is calculated for the first time, then it is recalculated with each glyph getting its adjustment. */
319     /** This one is used by scaling strategies: each glyph width is multiplied by this */
320     double textLengthMultiplier = 1;
321     /** This one is used by letterspacing strategy: to each glyph width, this is added */
322     double textLengthIncrement = 0;
323 
324     /** Get the actual spacing increment if it's due with the current values of above stuff, otherwise 0 */
325     double getTextLengthIncrementDue() const;
326     /** Get the actual scale multiplier if it's due with the current values of above stuff, otherwise 1 */
327     double getTextLengthMultiplierDue() const;
328 
329     /** Get actual length of layout, by summing span lengths. For one-line non-flowed text, just
330         the width; for multiline non-flowed, sum of lengths of all lines; for flowed text, sum of
331         scanline widths for all non-last lines plus text width of last line. */
332     double getActualLength() const;
333 
334 
335     // ************************** doing the actual flowing *************************
336 
337     /** \name Processing
338       The method to do the actual work of converting text into glyphs.
339     */
340     //@{
341 
342     /** Takes all the stuff you set with the members above here and creates
343     a load of glyphs for use with the members below here. All iterators on
344     this object will be invalidated (but can be fixed with validateIterator().
345     The implementation just creates a new Layout::Calculator and calls its
346     Calculator::Calculate() method, so if you want more details on the
347     internals, go there.
348       \return  false on failure.
349     */
350     bool calculateFlow();
351 
352     //@}
353 
354     // ************************** operating on the output glyphs *************************
355 
356     /** \name Output
357       Methods for reading and interpreting the output glyphs. See also
358       Layout::iterator.
359     */
360     //@{
361 
362     /** Returns true if there are some glyphs in this object, ie whether
363     computeFlow() has been called on a non-empty input since the object was
364     created or the last call to clear(). */
outputExists()365     inline bool outputExists() const
366         {return !_characters.empty();}
367 
368     /** Adds all the output glyphs to \a in_arena using the given \a paintbox.
369      \param in_arena  The arena to add the glyphs group to
370      \param paintbox  The current rendering tile
371     */
372     void show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const;
373 
374     /** Calculates the smallest rectangle completely enclosing all the
375     glyphs.
376       \param bounding_box  Where to store the box
377       \param transform     The transform to be applied to the entire object
378                            prior to calculating its bounds.
379     */
380     Geom::OptRect bounds(Geom::Affine const &transform, int start = -1, int length = -1) const;
381 
382     /** Sends all the glyphs to the given print context.
383      \param ctx   I have
384      \param pbox  no idea
385      \param dbox  what these
386      \param bbox  parameters
387      \param ctm   do yet
388     */
389     void print(SPPrintContext *ctx, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox, Geom::Affine const &ctm) const;
390 
391     /** Renders all the glyphs to the given Cairo rendering context.
392      \param ctx   The Cairo rendering context to be used
393      */
394     void showGlyphs(CairoRenderContext *ctx) const;
395 
396     /** Returns the font family of the indexed span */
397     Glib::ustring getFontFamily(unsigned span_index) const;
398 
399 #if DEBUG_TEXTLAYOUT_DUMPASTEXT
400     /** debug and unit test method. Creates a textual representation of the
401     contents of this object. The output is designed to be both human-readable
402     and comprehensible when diffed with a known-good dump. */
403     Glib::ustring dumpAsText() const;
404 #endif
405 
406     /** Moves all the glyphs in the structure so that the baseline of all
407     the characters sits neatly along the path specified. If the text has
408     more than one line the results are undefined. The 'align' means to
409     use the SVG align method as documented in SVG1.1 section 10.13.2.
410     NB: njh has suggested that it would be cool if we could flow from
411     shape to path and back again. This is possible, so this method will be
412     removed at some point.
413     A pointer to \a path is retained by the class for use by the cursor
414     positioning functions. */
415     void fitToPathAlign(SVGLength const &startOffset, Path const &path);
416 
417     /** Convert the specified range of characters into their bezier
418     outlines.
419     */
420     std::unique_ptr<SPCurve> convertToCurves(iterator const &from_glyph, iterator const &to_glyph) const;
421     std::unique_ptr<SPCurve> convertToCurves() const;
422 
423     /** Apply the given transform to all the output presently stored in
424     this object. This only transforms the glyph positions, The glyphs
425     themselves will not be transformed. */
426     void transform(Geom::Affine const &transform);
427 
428     //@}
429 
430     // **********
431 
432     /** \name Output (Iterators)
433       Methods for operating with the Layout::iterator class. The method
434       names ending with 'Index' return 0-based offsets of the number of
435       items since the beginning of the flow.
436     */
437     //@{
438 
439     /** Returns an iterator pointing at the first glyph of the flowed output.
440     The first glyph is also the first character, line, paragraph, etc. */
441     inline iterator begin() const;
442 
443     /** Returns an iterator pointing just past the end of the last glyph,
444     which is also just past the end of the last chunk, span, etc, etc. */
445     inline iterator end() const;
446 
447     /** Returns an iterator pointing at the given character index. This
448     index should be related to the result from a prior call to
449     iteratorToCharIndex(). */
450     inline iterator charIndexToIterator(int char_index) const;
451 
452     /** Returns the character index from the start of the flow represented
453     by the given iterator. This number isn't very useful, except for when
454     editing text it will stay valid across calls to computeFlow() and will
455     change in predictable ways when characters are added and removed. It's
456     also useful when transitioning old code. */
457     inline int iteratorToCharIndex(iterator const &it) const;
458 
459     /** Checks the validity of the given iterator over the current layout.
460     If it points to a position out of the bounds for this layout it will
461     be corrected to the nearest valid position. If you pass an iterator
462     belonging to a different layout it will be converted to one for this
463     layout. */
464     inline void validateIterator(iterator *it) const;
465 
466     /** Returns an iterator pointing to the cursor position for a mouse
467     click at the given coordinates. */
468     iterator getNearestCursorPositionTo(double x, double y) const;
469     inline iterator getNearestCursorPositionTo(Geom::Point const &point) const;
470 
471     /** Returns an iterator pointing to the letter whose bounding box contains
472     the given coordinates. end() if the point is not over any letter. The
473     iterator will \em not point at the specific glyph within the character. */
474     iterator getLetterAt(double x, double y) const;
475     inline iterator getLetterAt(Geom::Point &point) const;
476 
477     /* Returns an iterator pointing to the character in the output which
478     was created from the given input. If the character at the given byte
479     offset was removed (soft hyphens, for example) the next character after
480     it is returned. If no input was added with the given object, end() is
481     returned. If more than one input has the same object, the first will
482     be used regardless of the value of \a text_iterator. If
483     \a text_iterator is out of bounds, the first or last character belonging
484     to the given input will be returned accordingly.
485     iterator sourceToIterator(SPObject *source, Glib::ustring::const_iterator text_iterator) const;
486  */
487 
488     /** Returns an iterator pointing to the first character in the output
489     which was created from the given source. If \a source object is invalid,
490     end() is returned. If more than one input has the same object, the
491     first one will be used. */
492     iterator sourceToIterator(SPObject *source) const;
493 
494     // many functions acting on iterators, most of which are obvious
495     // also most of them don't check that \a it != end(). Be careful.
496 
497     /** Returns the bounding box of the given glyph, and its rotation.
498     The centre of rotation is the horizontal centre of the box at the
499     text baseline. */
500     Geom::OptRect glyphBoundingBox(iterator const &it, double *rotation) const;
501 
502     /** Returns the zero-based line number of the character pointed to by
503     \a it. */
504     inline unsigned lineIndex(iterator const &it) const;
505 
506     /** Returns the zero-based number of the shape which contains the
507     character pointed to by \a it. */
508     inline unsigned shapeIndex(iterator const &it) const;
509 
510     /** Returns true if the character at \a it is a whitespace, as defined
511     by Pango. This is not meant to be used for picking out words from the
512     output, use iterator::nextStartOfWord() and friends instead. */
513     inline bool isWhitespace(iterator const &it) const;
514 
515     /** Returns character pointed to by \a it. If \a it == end() the result is undefined. */
516     inline gchar characterAt(iterator const &it) const;
517 
518     /** Returns true if the text at \a it is hidden (i.e. overflowed). */
519     bool isHidden(iterator const &it) const;
520 
521     /** Discovers where the character pointed to by \a it came from, by
522     retrieving the object that was passed to the call to appendText() or
523     appendControlCode() which generated that output. If \a it == end()
524     then NULL is returned as the object. If the character was generated
525     from a call to appendText() then the optional \a text_iterator
526     parameter is set to point to the actual character, otherwise
527     \a text_iterator is unaltered. */
528     void getSourceOfCharacter(iterator const &it, SPObject **source, Glib::ustring::iterator *text_iterator = nullptr) const;
529 
530     /** For latin text, the left side of the character, on the baseline */
531     Geom::Point characterAnchorPoint(iterator const &it) const;
532 
533     /** For left aligned text, the leftmost end of the baseline
534     For rightmost text, the rightmost... you probably got it by now ;-)*/
535     std::optional<Geom::Point> baselineAnchorPoint() const;
536 
537     Geom::Path baseline() const;
538 
539     /** This is that value to apply to the x,y attributes of tspan role=line
540     elements, and hence it takes alignment into account. */
541     Geom::Point chunkAnchorPoint(iterator const &it) const;
542 
543     /** Returns the box extents (not ink extents) of the given character.
544     The centre of rotation is at the horizontal centre of the box on the
545     text baseline. */
546     Geom::Rect characterBoundingBox(iterator const &it, double *rotation = nullptr) const;
547 
548     /** Basically uses characterBoundingBox() on all the characters from
549     \a start to \a end and returns the union of these boxes. The return value
550     is a list of zero or more quadrilaterals specified by a group of four
551     points for each, thus size() is always a multiple of four. */
552     std::vector<Geom::Point> createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Affine const &transform) const;
553 
554     /** Returns true if \a it points to a character which is a valid cursor
555     position, as defined by Pango. */
556     inline bool isCursorPosition(iterator const &it) const;
557 
558     /** Gets the ideal cursor shape for a given iterator. The result is
559     undefined if \a it is not at a valid cursor position.
560       \param it        The location in the output
561       \param position  The pixel location of the centre of the 'bottom' of
562                        the cursor.
563       \param height    The height in pixels of the surrounding text
564       \param rotation  The angle to draw from \a position. Radians, zero up,
565                        increasing clockwise.
566     */
567     void queryCursorShape(iterator const &it, Geom::Point &position, double &height, double &rotation) const;
568 
569     /** Returns true if \a it points to a character which is a the start of
570     a word, as defined by Pango. */
571     inline bool isStartOfWord(iterator const &it) const;
572 
573     /** Returns true if \a it points to a character which is a the end of
574     a word, as defined by Pango. */
575     inline bool isEndOfWord(iterator const &it) const;
576 
577     /** Returns true if \a it points to a character which is a the start of
578     a sentence, as defined by Pango. */
579     inline bool isStartOfSentence(iterator const &it) const;
580 
581     /** Returns true if \a it points to a character which is a the end of
582     a sentence, as defined by Pango. */
583     inline bool isEndOfSentence(iterator const &it) const;
584 
585     /** Returns the zero-based number of the paragraph containing the
586     character pointed to by \a it. */
587     inline unsigned paragraphIndex(iterator const &it) const;
588 
589     /** Returns the actual alignment used for the paragraph containing
590     the character pointed to by \a it. This means that the CSS 'start'
591     and 'end' are correctly translated into LEFT or RIGHT according to
592     the paragraph's directionality. For vertical text, LEFT is top
593     alignment and RIGHT is bottom. */
594     inline Alignment paragraphAlignment(iterator const &it) const;
595 
596     /** Returns kerning information which could cause the current output
597     to be exactly reproduced if the letter and word spacings were zero and
598     full justification was not used. The x and y arrays are not used, but
599     they are cleared. The dx applied to the first character in a chunk
600     will always be zero. If the region between \a from and \a to crosses
601     a line break then the results may be surprising, and are undefined.
602     Trailing zeros on the returned arrays will be trimmed. */
603     void simulateLayoutUsingKerning(iterator const &from, iterator const &to, OptionalTextTagAttrs *result) const;
604 
605     //@}
606 
607 
608     /**
609      * Keep track of font metrics. Two use cases:
610      * 1. Keep track of ascent, descent, and x-height of an individual font.
611      * 2. Keep track of effective ascent and descent that includes half-leading.
612      *
613      * Note: Leading refers to the "external" leading which is added (subtracted) due to
614      * a computed value of 'line-height' that differs from 'font-size'. "Internal" leading
615      * which is specified inside a font is not used in CSS. The 'font-size' is based on
616      * the font's em size which is 'ascent' + 'descent'.
617      *
618      * This structure was renamed (and modified) from "LineHeight".
619      *
620      * It's useful for this to be public so that ScanlineMaker can use it.
621      */
622     class FontMetrics {
623 
624     public:
FontMetrics()625         FontMetrics() { reset(); }
626 
reset()627         void reset() {
628             ascent      =  0.8;
629             descent     =  0.2;
630             xheight     =  0.5;
631             ascent_max  =  0.8;
632             descent_max =  0.2;
633         }
634 
635         void set( font_instance *font );
636 
637         // CSS 2.1 dictates that font-size is based on em-size which is defined as ascent + descent
emSize()638         inline double emSize() const {return ascent + descent;}
639         // Alternatively name function for use 2.
lineSize()640         inline double lineSize() const { return ascent + descent; }
setZero()641         inline void setZero() {ascent = descent = xheight = ascent_max = descent_max = 0.0;}
642 
643         // For scaling for 'font-size'.
644         inline FontMetrics& operator*=(double x) {
645             ascent *= x; descent *= x; xheight *= x; ascent_max *= x; descent_max *= x;
646             return *this;
647         }
648 
649         /// Save the larger values of ascent and descent between this and other. Needed for laying
650         /// out a line with mixed font-sizes, fonts, or line spacings.
651         void max(FontMetrics const &other);
652 
653         /// Calculate the effective ascent and descent including half "leading".
654         void computeEffective( const double &line_height );
655 
getTypoAscent()656         inline double getTypoAscent()  const {return ascent; }
getTypoDescent()657         inline double getTypoDescent() const {return descent; }
getXHeight()658         inline double getXHeight()     const {return xheight; }
getMaxAscent()659         inline double getMaxAscent()   const {return ascent_max; }
getMaxDescent()660         inline double getMaxDescent()  const {return descent_max; }
661 
662         // private:
663         double ascent;      // Typographic ascent.
664         double descent;     // Typographic descent. (Normally positive).
665         double xheight;     // Height of 'x' measured from alphabetic baseline.
666         double ascent_max;  // Maximum ascent of all glyphs in font.
667         double descent_max; // Maximum descent of all glyphs in font.
668 
669     }; // End FontMetrics
670 
671     /** The strut is the minimum value used in calculating line height. */
672     FontMetrics strut;
673 
674 private:
675     /** Erases all the stuff set by the owner as input, ie #_input_stream
676     and #_input_wrap_shapes. */
677     void _clearInputObjects();
678 
679     /** Erases all the stuff output by computeFlow(). Glyphs and things. */
680     void _clearOutputObjects();
681 
682     static const gunichar UNICODE_SOFT_HYPHEN;
683 
684     // ******************* input flow
685 
686     enum InputStreamItemType {TEXT_SOURCE, CONTROL_CODE};
687 
688     class InputStreamItem {
689     public:
690         virtual ~InputStreamItem() = default;
691         virtual InputStreamItemType Type() =0;
692         SPObject *source;
693     };
694 
695     /** Represents a text item in the input stream. See #_input_stream.
696     Most of the members are copies of the values passed to appendText(). */
697     class InputStreamTextSource : public InputStreamItem {
698     public:
Type()699         InputStreamItemType Type() override {return TEXT_SOURCE;}
700         ~InputStreamTextSource() override;
701         Glib::ustring const *text;    /// owned by the caller
702         Glib::ustring::const_iterator text_begin, text_end;
703         int text_length;    /// in characters, from text_start to text_end only
704         SPStyle *style;
705         /** These vectors can (often will) be shorter than the text
706         in this source, but never longer. */
707         std::vector<SVGLength> x;
708         std::vector<SVGLength> y;
709         std::vector<SVGLength> dx;
710         std::vector<SVGLength> dy;
711         std::vector<SVGLength> rotate;
712         SVGLength textLength;
713         LengthAdjust lengthAdjust;
714         Glib::ustring lang;
715 
716         // a few functions for some of the more complicated style accesses
717         /// The return value must be freed with pango_font_description_free()
718         PangoFontDescription *styleGetFontDescription() const;
719         font_instance *styleGetFontInstance() const;
720         Direction styleGetBlockProgression() const;
721         SPCSSTextOrientation styleGetTextOrientation() const;
722         SPCSSBaseline styleGetDominantBaseline() const;
723         Alignment styleGetAlignment(Direction para_direction, bool try_text_align) const;
724     };
725 
726     /** Represents a control code item in the input stream. See
727     #_input_streams. All the members are copies of the values passed to
728     appendControlCode(). */
729     class InputStreamControlCode : public InputStreamItem {
730     public:
Type()731         InputStreamItemType Type() override {return CONTROL_CODE;}
732         TextControlCode code;
733         double ascent;
734         double descent;
735         double width;
736     };
737 
738     /** This is our internal storage for all the stuff passed to the
739     appendText() and appendControlCode() functions. */
740     std::vector<InputStreamItem*> _input_stream;
741 
742     /** The parameters to appendText() are allowed to be a little bit
743     complex. This copies them to be the right length and starting at zero.
744     We also don't want to write five bits of identical code just with
745     different variable names. */
746     static void _copyInputVector(std::vector<SVGLength> const &input_vector, unsigned input_offset, std::vector<SVGLength> *output_vector, size_t max_length);
747 
748     /** The overall block-progression of the whole flow. */
_blockProgression()749     inline Direction _blockProgression() const
750         {
751             if(!_input_stream.empty())
752                 return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetBlockProgression();
753             return TOP_TO_BOTTOM;
754         }
755 
756     /** The overall text-orientation of the whole flow. */
_blockTextOrientation()757     inline  SPCSSTextOrientation _blockTextOrientation() const
758         {
759             if(!_input_stream.empty())
760                 return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetTextOrientation();
761             return SP_CSS_TEXT_ORIENTATION_MIXED;
762         }
763 
764     /** The overall text-orientation of the whole flow. */
_blockBaseline()765     inline  SPCSSBaseline _blockBaseline() const
766         {
767             if(!_input_stream.empty())
768                 return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetDominantBaseline();
769             return SP_CSS_BASELINE_AUTO;
770         }
771 
772     /** so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM */
773     static bool _directions_are_orthogonal(Direction d1, Direction d2);
774 
775     /** If the output is empty callers still want to be able to call
776     queryCursorShape() and get a valid answer so, while #_input_wrap_shapes
777     can still be considered valid, we need to precompute the cursor shape
778     for this case. */
779     void _calculateCursorShapeForEmpty();
780 
781     struct CursorShape {
782         Geom::Point position;
783         double height;
784         double rotation;
785     } _empty_cursor_shape;
786 
787     // ******************* input shapes
788 
789     struct InputWrapShape {
790         Shape const *shape;        /// as passed to Layout::appendWrapShape()
791         DisplayAlign display_align;   /// as passed to Layout::appendWrapShape()
792     };
793     std::vector<InputWrapShape> _input_wrap_shapes;
794 
795     // ******************* output
796 
797     /** as passed to fitToPathAlign() */
798     Path const *_path_fitted = nullptr;
799 
800     struct Glyph;
801     struct Character;
802     struct Span;
803     struct Chunk;
804     struct Line;
805     struct Paragraph;
806 
807     // A glyph
808     struct Glyph {
809         int glyph;
810         unsigned in_character;
811         bool hidden;
812         float x;         /// relative to the start of the chunk
813         float y;         /// relative to the current line's baseline
814         float rotation;  /// absolute, modulo any object transforms, which we don't know about
815         Orientation orientation; /// Orientation of glyph in vertical text
816         float advance;   /// for positioning next glyph
817         float vertical_scale; /// to implement lengthAdjust="spacingAndGlyphs" that must scale glyphs only horizontally; instead we change font size and then undo that change vertically only
spanGlyph818         inline Span  const & span (Layout const *l) const {return                      l->_spans[l->_characters[in_character].in_span];}
chunkGlyph819         inline Chunk const & chunk(Layout const *l) const {return           l->_chunks[l->_spans[l->_characters[in_character].in_span].in_chunk];}
lineGlyph820         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];}
821     };
822 
823     // A unicode character
824     struct Character {
825         unsigned in_span;
826         float x;      /// relative to the start of the *span* (so we can do block-progression)
827         PangoLogAttr char_attributes;
828         gchar the_char = '#';
829         int in_glyph;   /// will be -1 if this character has no visual representation
spanCharacter830         inline Span      const & span     (Layout const *l) const {return                                     l->_spans[in_span];}
chunkCharacter831         inline Chunk     const & chunk    (Layout const *l) const {return                          l->_chunks[l->_spans[in_span].in_chunk];}
lineCharacter832         inline Line      const & line     (Layout const *l) const {return                l->_lines[l->_chunks[l->_spans[in_span].in_chunk].in_line];}
paragraphCharacter833         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];}
834         // 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
835     };
836 
837     // A collection of characters that share the same style and position start (<text> or <tspan> x, y attributes).
838     struct Span {
839         unsigned in_chunk;
840         font_instance *font;
841         float font_size;
842         float x_start;   /// relative to the start of the chunk
843         float x_end;     /// relative to the start of the chunk
844         float y_offset;  /// relative to line baseline (without baseline shift)
widthSpan845         inline float width() const {return std::abs(x_start - x_end);}
846         FontMetrics line_height;
847         double baseline_shift;  /// relative to the line's baseline (CSS)
848         SPCSSTextOrientation text_orientation;
849         Direction direction;     /// See CSS3 section 3.2. Either rtl or ltr
850         Direction block_progression;  /// See CSS3 section 3.2. The direction in which lines go.
851         unsigned in_input_stream_item;
852         Glib::ustring::const_iterator input_stream_first_character;
chunkSpan853         inline Chunk     const & chunk    (Layout const *l) const {return                          l->_chunks[in_chunk];                       }
lineSpan854         inline Line      const & line     (Layout const *l) const {return                l->_lines[l->_chunks[in_chunk].in_line];              }
paragraphSpan855         inline Paragraph const & paragraph(Layout const *l) const {return l->_paragraphs[l->_lines[l->_chunks[in_chunk].in_line].in_paragraph];}
856     };
857 
858     // A part of a line that is not broken.
859     struct Chunk {
860         unsigned in_line;
861         double left_x;
862     };
863 
864     // A line of text. Depending on the shape, it may contain one or more chunks.
865     struct Line {
866         unsigned in_paragraph;
867         double baseline_y;
868         unsigned in_shape;
869         bool hidden;
870     };
871 
872     // A paragraph. SVG 2 does not contain native paragraphs.
873     struct Paragraph {
874         Direction base_direction;    /// can be overridden by child Span objects
875         Alignment alignment;
876     };
877 
878     std::vector<Paragraph> _paragraphs;
879     std::vector<Line> _lines;
880     std::vector<Chunk> _chunks;
881     std::vector<Span> _spans;
882     std::vector<Character> _characters;
883     std::vector<Glyph> _glyphs;
884 
885     /** gets the overall matrix that transforms the given glyph from local
886     space to world space. */
887     void _getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const;
888 
889     // loads of functions to drill down the object tree, all of them
890     // annoyingly similar and all of them requiring predicate functors.
891     // I'll be buggered if I can find a way to make it work with
892     // functions or with a templated functor, so macros it is.
893 #define EMIT_PREDICATE(name, object_type, index_generator)                  \
894     class name {                                                            \
895         Layout const * const _flow;                                         \
896     public:                                                                 \
897         inline name(Layout const *flow) : _flow(flow) {}                    \
898         inline bool operator()(object_type const &object, unsigned index)   \
899             {g_assert(_flow); return index_generator < index;}              \
900     }
901 // end of macro
902     EMIT_PREDICATE(PredicateLineToSpan,        Span,      _flow->_chunks[object.in_chunk].in_line);
903     EMIT_PREDICATE(PredicateLineToCharacter,   Character, _flow->_chunks[_flow->_spans[object.in_span].in_chunk].in_line);
904     EMIT_PREDICATE(PredicateSpanToCharacter,   Character, object.in_span);
905     EMIT_PREDICATE(PredicateSourceToCharacter, Character, _flow->_spans[object.in_span].in_input_stream_item);
906 
_lineToSpan(unsigned line_index)907     inline unsigned _lineToSpan(unsigned line_index) const
908         {return std::lower_bound(_spans.begin(), _spans.end(), line_index, PredicateLineToSpan(this)) - _spans.begin();}
_lineToCharacter(unsigned line_index)909     inline unsigned _lineToCharacter(unsigned line_index) const
910         {return std::lower_bound(_characters.begin(), _characters.end(), line_index, PredicateLineToCharacter(this)) - _characters.begin();}
_spanToCharacter(unsigned span_index)911     inline unsigned _spanToCharacter(unsigned span_index) const
912         {return std::lower_bound(_characters.begin(), _characters.end(), span_index, PredicateSpanToCharacter(this)) - _characters.begin();}
_sourceToCharacter(unsigned source_index)913     inline unsigned _sourceToCharacter(unsigned source_index) const
914         {return std::lower_bound(_characters.begin(), _characters.end(), source_index, PredicateSourceToCharacter(this)) - _characters.begin();}
915 
916     /** given an x and y coordinate and a line number, returns an iterator
917     pointing to the closest cursor position on that line to the
918     coordinate.
919     ('y' is needed to handle cases where multiline text is simulated via the 'y' attribute.) */
920     iterator _cursorXOnLineToIterator(unsigned line_index, double local_x, double local_y = 0) const;
921 
922     /** calculates the width of a chunk, which is the largest x
923     coordinate (start or end) of the spans contained within it. */
924     double _getChunkWidth(unsigned chunk_index) const;
925 };
926 
927 /** \brief Holds a position within the glyph output of Layout.
928 
929 Used to access the output of a Layout, query information and generally
930 move around in it. See Layout for a glossary of the names of functions.
931 
932 I'm not going to document all the methods because most of their names make
933 their function self-evident.
934 
935 A lot of the functions would do the same thing in a naive implementation
936 for latin-only text, for example nextCharacter(), nextCursorPosition() and
937 cursorRight(). Generally it's fairly obvious which one you should use in a
938 given situation, but sometimes you might need to put some thought in to it.
939 
940 All the methods return false if the requested action would have caused the
941 current position to move out of bounds. In this case the position is moved
942 to either begin() or end(), depending on which direction you were going.
943 
944 Note that some characters do not have a glyph representation (eg line
945 breaks), so if you try using prev/nextGlyph() from one of these you're
946 heading for a crash.
947 */
948 class Layout::iterator {
949 public:
950     friend class Layout;
951     // this is just so you can create uninitialised iterators - don't actually try to use one
iterator()952     iterator() :
953         _parent_layout(nullptr),
954         _glyph_index(-1),
955         _char_index(0),
956         _cursor_moving_vertically(false),
957         _x_coordinate(0.0){}
958     // no copy constructor required, the default does what we want
959     bool operator== (iterator const &other) const
960         {return _glyph_index == other._glyph_index && _char_index == other._char_index;}
961     bool operator!= (iterator const &other) const
962         {return _glyph_index != other._glyph_index || _char_index != other._char_index;}
963 
964     /* mustn't compare _glyph_index in these operators because for characters
965     that don't have glyphs (line breaks, elided soft hyphens, etc), the glyph
966     index is -1 which makes them not well-ordered. To be honest, iterating by
967     glyphs is not very useful and should be avoided. */
968     bool operator< (iterator const &other) const
969         {return _char_index < other._char_index;}
970     bool operator<= (iterator const &other) const
971         {return _char_index <= other._char_index;}
972     bool operator> (iterator const &other) const
973         {return _char_index > other._char_index;}
974     bool operator>= (iterator const &other) const
975         {return _char_index >= other._char_index;}
976 
977     /* **** visual-oriented methods **** */
978 
979     //glyphs
980     inline bool prevGlyph();
981     inline bool nextGlyph();
982 
983     //span
984     bool prevStartOfSpan();
985     bool thisStartOfSpan();
986     bool nextStartOfSpan();
987 
988     //chunk
989     bool prevStartOfChunk();
990     bool thisStartOfChunk();
991     bool nextStartOfChunk();
992 
993     //line
994     bool prevStartOfLine();
995     bool thisStartOfLine();
996     bool nextStartOfLine();
997     bool thisEndOfLine();
998 
999     //shape
1000     bool prevStartOfShape();
1001     bool thisStartOfShape();
1002     bool nextStartOfShape();
1003 
1004     /* **** text-oriented methods **** */
1005 
1006     //characters
1007     inline bool nextCharacter();
1008     inline bool prevCharacter();
1009 
1010     bool nextCursorPosition();
1011     bool prevCursorPosition();
1012     bool nextLineCursor(int n = 1);
1013     bool prevLineCursor(int n = 1);
1014 
1015     //words
1016     bool nextStartOfWord();
1017     bool prevStartOfWord();
1018     bool nextEndOfWord();
1019     bool prevEndOfWord();
1020 
1021     //sentences
1022     bool nextStartOfSentence();
1023     bool prevStartOfSentence();
1024     bool nextEndOfSentence();
1025     bool prevEndOfSentence();
1026 
1027     //paragraphs
1028     bool prevStartOfParagraph();
1029     bool thisStartOfParagraph();
1030     bool nextStartOfParagraph();
1031     //no endOfPara methods because that's just the previous char
1032 
1033     //sources
1034     bool prevStartOfSource();
1035     bool thisStartOfSource();
1036     bool nextStartOfSource();
1037 
1038     //logical cursor movement
1039     bool cursorUp(int n = 1);
1040     bool cursorDown(int n = 1);
1041     bool cursorLeft();
1042     bool cursorRight();
1043 
1044     //logical cursor movement (by word or paragraph)
1045     bool cursorUpWithControl();
1046     bool cursorDownWithControl();
1047     bool cursorLeftWithControl();
1048     bool cursorRightWithControl();
1049 
1050 private:
1051     Layout const *_parent_layout;
1052     int _glyph_index;      /// index into Layout::glyphs, or -1
1053     unsigned _char_index;       /// index into Layout::character
1054     bool _cursor_moving_vertically;
1055     /** for cursor up/down movement we must maintain the x position where
1056     we started so the cursor doesn't 'drift' left or right with the repeated
1057     quantization to character boundaries. */
1058     double _x_coordinate;
1059 
iterator(Layout const * p,unsigned c,int g)1060     inline iterator(Layout const *p, unsigned c, int g)
1061         : _parent_layout(p), _glyph_index(g), _char_index(c), _cursor_moving_vertically(false), _x_coordinate(0.0) {}
iterator(Layout const * p,unsigned c)1062     inline iterator(Layout const *p, unsigned c)
1063         : _parent_layout(p), _glyph_index(p->_characters[c].in_glyph), _char_index(c), _cursor_moving_vertically(false), _x_coordinate(0.0) {}
1064     // no dtor required
1065     void beginCursorUpDown();  /// stores the current x coordinate so that the cursor won't drift. See #_x_coordinate
1066 
1067     /** moves forward or backwards one cursor position according to the
1068     directionality of the current paragraph, but ignoring block progression.
1069     Helper for the cursor*() functions. */
1070     bool _cursorLeftOrRightLocalX(Direction direction);
1071 
1072     /** moves forward or backwards by until the next character with
1073     is_word_start according to the directionality of the current paragraph,
1074     but ignoring block progression. Helper for the cursor*WithControl()
1075     functions. */
1076     bool _cursorLeftOrRightLocalXByWord(Direction direction);
1077 };
1078 
1079 // ************************** inline methods
1080 
begin()1081 inline Layout::iterator Layout::begin() const
1082     {return iterator(this, 0, 0);}
1083 
end()1084 inline Layout::iterator Layout::end() const
1085     {return iterator(this, _characters.size(), _glyphs.size());}
1086 
charIndexToIterator(int char_index)1087 inline Layout::iterator Layout::charIndexToIterator(int char_index) const
1088 {
1089     if (char_index < 0) return begin();
1090     if (char_index >= (int)_characters.size()) return end();
1091     return iterator(this, char_index);
1092 }
1093 
iteratorToCharIndex(Layout::iterator const & it)1094 inline int Layout::iteratorToCharIndex(Layout::iterator const &it) const
1095     {return it._char_index;}
1096 
validateIterator(Layout::iterator * it)1097 inline void Layout::validateIterator(Layout::iterator *it) const
1098 {
1099     it->_parent_layout = this;
1100     if (it->_char_index >= _characters.size()) {
1101         it->_char_index = _characters.size();
1102         it->_glyph_index = _glyphs.size();
1103     } else
1104         it->_glyph_index = _characters[it->_char_index].in_glyph;
1105 }
1106 
getNearestCursorPositionTo(Geom::Point const & point)1107 inline Layout::iterator Layout::getNearestCursorPositionTo(Geom::Point const &point) const
1108     {return getNearestCursorPositionTo(point[0], point[1]);}
1109 
getLetterAt(Geom::Point & point)1110 inline Layout::iterator Layout::getLetterAt(Geom::Point &point) const
1111     {return getLetterAt(point[0], point[1]);}
1112 
lineIndex(iterator const & it)1113 inline unsigned Layout::lineIndex(iterator const &it) const
1114     {return it._char_index == _characters.size() ? _lines.size() - 1 : _characters[it._char_index].chunk(this).in_line;}
1115 
shapeIndex(iterator const & it)1116 inline unsigned Layout::shapeIndex(iterator const &it) const
1117     {return it._char_index == _characters.size() ? _input_wrap_shapes.size() - 1 : _characters[it._char_index].line(this).in_shape;}
1118 
isWhitespace(iterator const & it)1119 inline bool Layout::isWhitespace(iterator const &it) const
1120     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_white;}
1121 
characterAt(iterator const & it)1122 inline gchar Layout::characterAt(iterator const &it) const
1123 {
1124     return _characters[it._char_index].the_char;
1125 }
1126 
isCursorPosition(iterator const & it)1127 inline bool Layout::isCursorPosition(iterator const &it) const
1128     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_cursor_position;}
1129 
isStartOfWord(iterator const & it)1130 inline bool Layout::isStartOfWord(iterator const &it) const
1131     {return it._char_index != _characters.size() && _characters[it._char_index].char_attributes.is_word_start;}
1132 
isEndOfWord(iterator const & it)1133 inline bool Layout::isEndOfWord(iterator const &it) const
1134     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_word_end;}
1135 
isStartOfSentence(iterator const & it)1136 inline bool Layout::isStartOfSentence(iterator const &it) const
1137     {return it._char_index != _characters.size() && _characters[it._char_index].char_attributes.is_sentence_start;}
1138 
isEndOfSentence(iterator const & it)1139 inline bool Layout::isEndOfSentence(iterator const &it) const
1140     {return it._char_index == _characters.size() || _characters[it._char_index].char_attributes.is_sentence_end;}
1141 
paragraphIndex(iterator const & it)1142 inline unsigned Layout::paragraphIndex(iterator const &it) const
1143     {return it._char_index == _characters.size() ? _paragraphs.size() - 1 : _characters[it._char_index].line(this).in_paragraph;}
1144 
paragraphAlignment(iterator const & it)1145 inline Layout::Alignment Layout::paragraphAlignment(iterator const &it) const
1146     {return (_paragraphs.size() == 0) ? NONE : _paragraphs[paragraphIndex(it)].alignment;}
1147 
nextGlyph()1148 inline bool Layout::iterator::nextGlyph()
1149 {
1150     _cursor_moving_vertically = false;
1151     if (_glyph_index >= (int)_parent_layout->_glyphs.size() - 1) {
1152         if (_glyph_index == (int)_parent_layout->_glyphs.size()) return false;
1153         _char_index = _parent_layout->_characters.size();
1154         _glyph_index = _parent_layout->_glyphs.size();
1155     }
1156     else _char_index = _parent_layout->_glyphs[++_glyph_index].in_character;
1157     return true;
1158 }
1159 
prevGlyph()1160 inline bool Layout::iterator::prevGlyph()
1161 {
1162     _cursor_moving_vertically = false;
1163     if (_glyph_index == 0) return false;
1164     _char_index = _parent_layout->_glyphs[--_glyph_index].in_character;
1165     return true;
1166 }
1167 
nextCharacter()1168 inline bool Layout::iterator::nextCharacter()
1169 {
1170     _cursor_moving_vertically = false;
1171     if (_char_index + 1 >= _parent_layout->_characters.size()) {
1172         if (_char_index == _parent_layout->_characters.size()) return false;
1173         _char_index = _parent_layout->_characters.size();
1174         _glyph_index = _parent_layout->_glyphs.size();
1175     }
1176     else _glyph_index = _parent_layout->_characters[++_char_index].in_glyph;
1177     return true;
1178 }
1179 
prevCharacter()1180 inline bool Layout::iterator::prevCharacter()
1181 {
1182     _cursor_moving_vertically = false;
1183     if (_char_index == 0) return false;
1184     _glyph_index = _parent_layout->_characters[--_char_index].in_glyph;
1185     return true;
1186 }
1187 
1188 }//namespace Text
1189 }//namespace Inkscape
1190 
1191 std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics &f);
1192 std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics *f);
1193 
1194 
1195 #endif
1196 
1197 
1198 /*
1199   Local Variables:
1200   mode:c++
1201   c-file-style:"stroustrup"
1202   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1203   indent-tabs-mode:nil
1204   fill-column:99
1205   End:
1206 */
1207 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
1208