1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
29 //==============================================================================
30 /**
31     A Pre-formatted piece of text, which may contain multiple fonts and colours.
32 
33     A TextLayout is created from an AttributedString, and once created can be
34     quickly drawn into a Graphics context.
35 
36     @see AttributedString
37 
38     @tags{Graphics}
39 */
40 class JUCE_API  TextLayout  final
41 {
42 private:
43     template <typename Iterator>
44     class DereferencingIterator
45     {
46     public:
47         using value_type = typename std::remove_reference<decltype(**std::declval<Iterator>())>::type;
48         using difference_type = typename std::iterator_traits<Iterator>::difference_type;
49         using pointer = value_type*;
50         using reference = value_type&;
51         using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
52 
DereferencingIterator(Iterator in)53         explicit DereferencingIterator (Iterator in) : iterator (std::move (in)) {}
54 
55         DereferencingIterator& operator+= (difference_type distance)
56         {
57             iterator += distance;
58             return *this;
59         }
60 
61         friend DereferencingIterator operator+ (DereferencingIterator i, difference_type d) { return i += d; }
62         friend DereferencingIterator operator+ (difference_type d, DereferencingIterator i) { return i += d; }
63 
64         DereferencingIterator& operator-= (difference_type distance)
65         {
66             iterator -= distance;
67             return *this;
68         }
69 
70         friend DereferencingIterator operator- (DereferencingIterator i, difference_type d) { return i -= d; }
71 
72         friend difference_type operator- (DereferencingIterator a, DereferencingIterator b)   { return a.iterator - b.iterator; }
73 
74         reference operator[] (difference_type d) const { return *iterator[d]; }
75 
76         friend bool operator<  (DereferencingIterator a, DereferencingIterator b) { return a.iterator <  b.iterator; }
77         friend bool operator<= (DereferencingIterator a, DereferencingIterator b) { return a.iterator <= b.iterator; }
78         friend bool operator>  (DereferencingIterator a, DereferencingIterator b) { return a.iterator >  b.iterator; }
79         friend bool operator>= (DereferencingIterator a, DereferencingIterator b) { return a.iterator >= b.iterator; }
80         friend bool operator== (DereferencingIterator a, DereferencingIterator b) { return a.iterator == b.iterator; }
81         friend bool operator!= (DereferencingIterator a, DereferencingIterator b) { return a.iterator != b.iterator; }
82 
83         DereferencingIterator& operator++()           { ++iterator; return *this; }
84         DereferencingIterator& operator--()           { --iterator; return *this; }
85         DereferencingIterator  operator++ (int) const { DereferencingIterator copy (*this); ++(*this); return copy; }
86         DereferencingIterator  operator-- (int) const { DereferencingIterator copy (*this); --(*this); return copy; }
87 
88         reference operator* () const { return **iterator; }
89         pointer   operator->() const { return  *iterator; }
90 
91     private:
92         Iterator iterator;
93     };
94 
95 public:
96     /** Creates an empty layout.
97         Having created a TextLayout, you can populate it using createLayout() or
98         createLayoutWithBalancedLineLengths().
99     */
100     TextLayout();
101     TextLayout (const TextLayout&);
102     TextLayout& operator= (const TextLayout&);
103     TextLayout (TextLayout&&) noexcept;
104     TextLayout& operator= (TextLayout&&) noexcept;
105 
106     /** Destructor. */
107     ~TextLayout();
108 
109     //==============================================================================
110     /** Creates a layout from the given attributed string.
111         This will replace any data that is currently stored in the layout.
112     */
113     void createLayout (const AttributedString&, float maxWidth);
114 
115     /** Creates a layout from the given attributed string, given some size constraints.
116         This will replace any data that is currently stored in the layout.
117     */
118     void createLayout (const AttributedString&, float maxWidth, float maxHeight);
119 
120     /** Creates a layout, attempting to choose a width which results in lines
121         of a similar length.
122 
123         This will be slower than the normal createLayout method, but produces a
124         tidier result.
125     */
126     void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth);
127 
128     /** Creates a layout, attempting to choose a width which results in lines
129         of a similar length.
130 
131         This will be slower than the normal createLayout method, but produces a
132         tidier result.
133     */
134     void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth, float maxHeight);
135 
136     /** Draws the layout within the specified area.
137         The position of the text within the rectangle is controlled by the justification
138         flags set in the original AttributedString that was used to create this layout.
139     */
140     void draw (Graphics&, Rectangle<float> area) const;
141 
142     //==============================================================================
143     /** A positioned glyph. */
144     class JUCE_API  Glyph
145     {
146     public:
147         Glyph (int glyphCode, Point<float> anchor, float width) noexcept;
148         Glyph (const Glyph&) noexcept;
149         Glyph& operator= (const Glyph&) noexcept;
150         ~Glyph() noexcept;
151 
152         /** The code number of this glyph. */
153         int glyphCode;
154 
155         /** The glyph's anchor point - this is relative to the line's origin.
156             @see TextLayout::Line::lineOrigin
157         */
158         Point<float> anchor;
159 
160         float width;
161 
162     private:
163         JUCE_LEAK_DETECTOR (Glyph)
164     };
165 
166     //==============================================================================
167     /** A sequence of glyphs with a common font and colour. */
168     class JUCE_API  Run
169     {
170     public:
171         Run() noexcept;
172         Run (const Run&);
173         Run (Range<int> stringRange, int numGlyphsToPreallocate);
174         ~Run() noexcept;
175 
176         /** Returns the X position range which contains all the glyphs in this run. */
177         Range<float> getRunBoundsX() const noexcept;
178 
179         Font font;              /**< The run's font. */
180         Colour colour;          /**< The run's colour. */
181         Array<Glyph> glyphs;    /**< The glyphs in this run. */
182         Range<int> stringRange; /**< The character range that this run represents in the
183                                      original string that was used to create it. */
184     private:
185         Run& operator= (const Run&);
186         JUCE_LEAK_DETECTOR (Run)
187     };
188 
189     //==============================================================================
190     /** A line containing a sequence of glyph-runs. */
191     class JUCE_API  Line
192     {
193     public:
194         Line() noexcept;
195         Line (const Line&);
196         Line (Range<int> stringRange, Point<float> lineOrigin,
197               float ascent, float descent, float leading, int numRunsToPreallocate);
198         ~Line() noexcept;
199 
200         /** Returns the X position range which contains all the glyphs in this line. */
201         Range<float> getLineBoundsX() const noexcept;
202 
203         /** Returns the Y position range which contains all the glyphs in this line. */
204         Range<float> getLineBoundsY() const noexcept;
205 
206         /** Returns the smallest rectangle which contains all the glyphs in this line. */
207         Rectangle<float> getLineBounds() const noexcept;
208 
209         OwnedArray<Run> runs;           /**< The glyph-runs in this line. */
210         Range<int> stringRange;         /**< The character range that this line represents in the
211                                              original string that was used to create it. */
212         Point<float> lineOrigin;        /**< The line's baseline origin. */
213         float ascent, descent, leading;
214 
215     private:
216         Line& operator= (const Line&);
217         JUCE_LEAK_DETECTOR (Line)
218     };
219 
220     //==============================================================================
221     /** Returns the maximum width of the content. */
getWidth()222     float getWidth() const noexcept     { return width; }
223 
224     /** Returns the maximum height of the content. */
getHeight()225     float getHeight() const noexcept    { return height; }
226 
227     /** Returns the number of lines in the layout. */
getNumLines()228     int getNumLines() const noexcept    { return lines.size(); }
229 
230     /** Returns one of the lines. */
231     Line& getLine (int index) const noexcept;
232 
233     /** Adds a line to the layout. The layout will take ownership of this line object
234         and will delete it when it is no longer needed. */
235     void addLine (std::unique_ptr<Line>);
236 
237     /** Pre-allocates space for the specified number of lines. */
238     void ensureStorageAllocated (int numLinesNeeded);
239 
240     using       iterator = DereferencingIterator<      Line* const*>;
241     using const_iterator = DereferencingIterator<const Line* const*>;
242 
243     /** Returns an iterator over the lines of content */
begin()244           iterator  begin()       { return       iterator (lines.begin()); }
begin()245     const_iterator  begin() const { return const_iterator (lines.begin()); }
cbegin()246     const_iterator cbegin() const { return const_iterator (lines.begin()); }
247 
248     /** Returns an iterator over the lines of content */
end()249           iterator  end()       { return       iterator (lines.end()); }
end()250     const_iterator  end() const { return const_iterator (lines.end()); }
cend()251     const_iterator cend() const { return const_iterator (lines.end()); }
252 
253     /** If you modify the TextLayout after creating it, call this to compute
254         the new dimensions of the content.
255     */
256     void recalculateSize();
257 
258 private:
259     OwnedArray<Line> lines;
260     float width, height;
261     Justification justification;
262 
263     void createStandardLayout (const AttributedString&);
264     bool createNativeLayout (const AttributedString&);
265 
266     JUCE_LEAK_DETECTOR (TextLayout)
267 };
268 
269 } // namespace juce
270