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