Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgstextrenderer.h
3 : : -----------------
4 : : begin : September 2015
5 : : copyright : (C) Nyall Dawson
6 : : email : nyall dot dawson at gmail dot com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : :
16 : : #ifndef QGSTEXTRENDERER_H
17 : : #define QGSTEXTRENDERER_H
18 : :
19 : : #include "qgis_sip.h"
20 : : #include "qgis_core.h"
21 : : #include "qgstextblock.h"
22 : : #include "qgsrendercontext.h"
23 : : #include "qgstextformat.h"
24 : :
25 : : #include <QPicture>
26 : :
27 : : class QgsTextDocument;
28 : :
29 : : /**
30 : : * \class QgsTextRenderer
31 : : * \ingroup core
32 : : * \brief Handles rendering text using rich formatting options, including drop shadows, buffers
33 : : * and background shapes.
34 : : * \since QGIS 3.0
35 : : */
36 : : class CORE_EXPORT QgsTextRenderer
37 : : {
38 : : public:
39 : :
40 : : //! Draw mode to calculate width and height
41 : : enum DrawMode
42 : : {
43 : : Rect = 0, //!< Text within rectangle draw mode
44 : : Point, //!< Text at point of origin draw mode
45 : : Label, //!< Label-specific draw mode
46 : : };
47 : :
48 : : //! Components of text
49 : : enum TextPart
50 : : {
51 : : Text = 0, //!< Text component
52 : : Buffer, //!< Buffer component
53 : : Background, //!< Background shape
54 : : Shadow, //!< Drop shadow
55 : : };
56 : :
57 : : //! Horizontal alignment
58 : : enum HAlignment
59 : : {
60 : : AlignLeft = 0, //!< Left align
61 : : AlignCenter, //!< Center align
62 : : AlignRight, //!< Right align
63 : : AlignJustify, //!< Justify align
64 : : };
65 : :
66 : : /**
67 : : * Converts a Qt horizontal \a alignment flag to a QgsTextRenderer::HAlignment value.
68 : : *
69 : : * \see convertQtVAlignment()
70 : : * \since QGIS 3.16
71 : : */
72 : : static HAlignment convertQtHAlignment( Qt::Alignment alignment );
73 : :
74 : : /**
75 : : * Vertical alignment
76 : : * \since QGIS 3.16
77 : : */
78 : : enum VAlignment
79 : : {
80 : : AlignTop = 0, //!< Align to top
81 : : AlignVCenter, //!< Center align
82 : : AlignBottom, //!< Align to bottom
83 : : };
84 : :
85 : : /**
86 : : * Converts a Qt vertical \a alignment flag to a QgsTextRenderer::VAlignment value.
87 : : *
88 : : * \see convertQtHAlignment()
89 : : * \since QGIS 3.16
90 : : */
91 : : static VAlignment convertQtVAlignment( Qt::Alignment alignment );
92 : :
93 : : /**
94 : : * Calculates pixel size (considering output size should be in pixel or map units, scale factors and optionally oversampling)
95 : : * \param size size to convert
96 : : * \param c rendercontext
97 : : * \param unit size units
98 : : * \param mapUnitScale a mapUnitScale clamper
99 : : * \returns font pixel size
100 : : */
101 : : static int sizeToPixel( double size, const QgsRenderContext &c, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &mapUnitScale = QgsMapUnitScale() );
102 : :
103 : : // TODO QGIS 4.0 -- remove drawAsOutlines from below methods!
104 : :
105 : : /**
106 : : * Draws text within a rectangle using the specified settings.
107 : : * \param rect destination rectangle for text
108 : : * \param rotation text rotation
109 : : * \param alignment horizontal alignment
110 : : * \param textLines list of lines of text to draw
111 : : * \param context render context
112 : : * \param format text format
113 : : * \param drawAsOutlines set to FALSE to render text as text. This allows outputs to
114 : : * formats like SVG to maintain text as text objects, but at the cost of degraded
115 : : * rendering and may result in side effects like misaligned text buffers. This setting is deprecated and has no effect
116 : : * as of QGIS 3.4.3 and the text format should be set using QgsRenderContext::setTextRenderFormat() instead.
117 : : * \param vAlignment vertical alignment (since QGIS 3.16)
118 : : */
119 : : static void drawText( const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines,
120 : : QgsRenderContext &context, const QgsTextFormat &format,
121 : : bool drawAsOutlines = true, VAlignment vAlignment = AlignTop );
122 : :
123 : : /**
124 : : * Draws text at a point origin using the specified settings.
125 : : * \param point origin of text
126 : : * \param rotation text rotation
127 : : * \param alignment horizontal alignment
128 : : * \param textLines list of lines of text to draw
129 : : * \param context render context
130 : : * \param format text format
131 : : * \param drawAsOutlines set to FALSE to render text as text. This allows outputs to
132 : : * formats like SVG to maintain text as text objects, but at the cost of degraded
133 : : * rendering and may result in side effects like misaligned text buffers. This setting is deprecated and has no effect
134 : : * as of QGIS 3.4.3 and the text format should be set using QgsRenderContext::setTextRenderFormat() instead.
135 : : */
136 : : static void drawText( QPointF point, double rotation, HAlignment alignment, const QStringList &textLines,
137 : : QgsRenderContext &context, const QgsTextFormat &format,
138 : : bool drawAsOutlines = true );
139 : :
140 : : /**
141 : : * Draws a single component of rendered text using the specified settings.
142 : : * \param rect destination rectangle for text
143 : : * \param rotation text rotation
144 : : * \param alignment horizontal alignment
145 : : * \param textLines list of lines of text to draw
146 : : * \param context render context
147 : : * \param format text format
148 : : * \param part component of text to draw. Note that Shadow parts cannot be drawn
149 : : * individually and instead are drawn with their associated part (e.g., drawn together
150 : : * with the text or background parts)
151 : : * \param drawAsOutlines set to FALSE to render text as text. This allows outputs to
152 : : * formats like SVG to maintain text as text objects, but at the cost of degraded
153 : : * rendering and may result in side effects like misaligned text buffers. This setting is deprecated and has no effect
154 : : * as of QGIS 3.4.3 and the text format should be set using QgsRenderContext::setTextRenderFormat() instead.
155 : : *
156 : : * \deprecated Private API only, will be removed in 4.0
157 : : */
158 : : Q_DECL_DEPRECATED static void drawPart( const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines,
159 : : QgsRenderContext &context, const QgsTextFormat &format,
160 : : TextPart part, bool drawAsOutlines = true ) SIP_DEPRECATED;
161 : :
162 : : /**
163 : : * Draws a single component of rendered text using the specified settings.
164 : : * \param origin origin for start of text. Y coordinate will be used as baseline.
165 : : * \param rotation text rotation
166 : : * \param alignment horizontal alignment
167 : : * \param textLines list of lines of text to draw
168 : : * \param context render context
169 : : * \param format text format
170 : : * \param part component of text to draw. Note that Shadow parts cannot be drawn
171 : : * individually and instead are drawn with their associated part (e.g., drawn together
172 : : * with the text or background parts)
173 : : * \param drawAsOutlines set to FALSE to render text as text. This allows outputs to
174 : : * formats like SVG to maintain text as text objects, but at the cost of degraded
175 : : * rendering and may result in side effects like misaligned text buffers. This setting is deprecated and has no effect
176 : : * as of QGIS 3.4.3 and the text format should be set using QgsRenderContext::setTextRenderFormat() instead.
177 : : *
178 : : * \deprecated Private API only, will be removed in 4.0
179 : : */
180 : : Q_DECL_DEPRECATED static void drawPart( QPointF origin, double rotation, HAlignment alignment, const QStringList &textLines,
181 : : QgsRenderContext &context, const QgsTextFormat &format,
182 : : TextPart part, bool drawAsOutlines = true ) SIP_DEPRECATED;
183 : :
184 : : /**
185 : : * Returns the font metrics for the given text \a format, when rendered
186 : : * in the specified render \a context. The font metrics will take into account
187 : : * all scaling required by the render context.
188 : : *
189 : : * The optional \a scaleFactor argument can specify a font size scaling factor. It is recommended to set this to
190 : : * QgsTextRenderer::FONT_WORKAROUND_SCALE and then manually scale painter devices or calculations
191 : : * based on the resultant font metrics. Failure to do so will result in poor quality text rendering
192 : : * at small font sizes.
193 : : *
194 : : * \since QGIS 3.2
195 : : */
196 : : static QFontMetricsF fontMetrics( QgsRenderContext &context, const QgsTextFormat &format, double scaleFactor = 1.0 );
197 : :
198 : : /**
199 : : * Returns the width of a text based on a given format.
200 : : * \param context render context
201 : : * \param format text format
202 : : * \param textLines list of lines of text to calculate width from
203 : : * \param fontMetrics font metrics
204 : : */
205 : : static double textWidth( const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines,
206 : : QFontMetricsF *fontMetrics = nullptr );
207 : :
208 : : /**
209 : : * Returns the height of a text based on a given format.
210 : : * \param context render context
211 : : * \param format text format
212 : : * \param textLines list of lines of text to calculate width from
213 : : * \param mode draw mode
214 : : * \param fontMetrics font metrics
215 : : */
216 : : static double textHeight( const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode = Point,
217 : : QFontMetricsF *fontMetrics = nullptr );
218 : :
219 : : /**
220 : : * Returns the height of a character when rendered with the specified text \a format.
221 : : *
222 : : * \param context render context
223 : : * \param format text format
224 : : * \param character character to determine height of. If \a character is invalid, then the maximum character height will be returned.
225 : : * \param includeEffects if TRUE, then the size of formatting effects such as buffers and shadows will be considered in the
226 : : * returned height. If FALSE, then the returned size considers the character only.
227 : : *
228 : : * \since QGIS 3.16
229 : : */
230 : : static double textHeight( const QgsRenderContext &context, const QgsTextFormat &format, QChar character, bool includeEffects = false );
231 : :
232 : : /**
233 : : * Scale factor for upscaling font sizes and downscaling destination painter devices.
234 : : *
235 : : * Using this scale factor and manually adjusting any font metric based calculations results in more stable
236 : : * font metrics and sizes for small font sizes.
237 : : *
238 : : * \since QGIS 3.16
239 : : */
240 : : static constexpr double FONT_WORKAROUND_SCALE = 10;
241 : :
242 : : private:
243 : :
244 : 0 : struct Component
245 : : {
246 : : //! Block to render
247 : : QgsTextBlock block;
248 : : //! Current origin point for painting (generally current painter rotation point)
249 : : QPointF origin;
250 : : //! Whether to translate the painter to supplied origin
251 : 0 : bool useOrigin = false;
252 : : //! Any rotation to be applied to painter (in radians)
253 : 0 : double rotation = 0.0;
254 : : //! Any rotation to be applied to painter (in radians) after initial rotation
255 : 0 : double rotationOffset = 0.0;
256 : : //! Current center point of label component, after rotation
257 : : QPointF center;
258 : : //! Width and height of label component, transformed and ready for painting
259 : : QSizeF size;
260 : : //! Any translation offsets to be applied before painting, transformed and ready for painting
261 : : QPointF offset;
262 : : //! A stored QPicture of painting for the component
263 : : QPicture picture;
264 : :
265 : : /**
266 : : * Buffer for component to accommodate graphic items ignored by QPicture,
267 : : * e.g. half-width of an applied QPen, which would extend beyond boundingRect() of QPicture
268 : : */
269 : 0 : double pictureBuffer = 0.0;
270 : : //! A ratio of native painter dpi and that of rendering context's painter
271 : 0 : double dpiRatio = 1.0;
272 : : //! Horizontal alignment
273 : 0 : HAlignment hAlign = AlignLeft;
274 : :
275 : : //! Any additional word spacing to apply while rendering component
276 : 0 : double extraWordSpacing = 0;
277 : : //! Any additional letter spacing to apply while rendering component
278 : 0 : double extraLetterSpacing = 0;
279 : : };
280 : :
281 : : static double textWidth( const QgsRenderContext &context, const QgsTextFormat &format, const QgsTextDocument &document );
282 : : static double textHeight( const QgsRenderContext &context, const QgsTextFormat &format, const QgsTextDocument &document, DrawMode mode = Point );
283 : :
284 : : /**
285 : : * Draws a single component of rendered text using the specified settings.
286 : : * \param rect destination rectangle for text
287 : : * \param rotation text rotation
288 : : * \param alignment horizontal alignment
289 : : * \param vAlignment vertical alignment
290 : : * \param document text document to draw
291 : : * \param context render context
292 : : * \param format text format
293 : : * \param part component of text to draw. Note that Shadow parts cannot be drawn
294 : : * individually and instead are drawn with their associated part (e.g., drawn together
295 : : * with the text or background parts)
296 : : * \note Not available in Python bindings
297 : : * \since QGIS 3.14
298 : : */
299 : : static void drawPart( const QRectF &rect, double rotation, HAlignment alignment, VAlignment vAlignment, const QgsTextDocument &document,
300 : : QgsRenderContext &context, const QgsTextFormat &format,
301 : : TextPart part );
302 : :
303 : : /**
304 : : * Draws a single component of rendered text using the specified settings.
305 : : * \param origin origin for start of text. Y coordinate will be used as baseline.
306 : : * \param rotation text rotation
307 : : * \param alignment horizontal alignment
308 : : * \param document document to draw
309 : : * \param context render context
310 : : * \param format text format
311 : : * \param part component of text to draw. Note that Shadow parts cannot be drawn
312 : : * individually and instead are drawn with their associated part (e.g., drawn together
313 : : * with the text or background parts)
314 : : * \note Not available in Python bindings
315 : : * \since QGIS 3.14
316 : : */
317 : : static void drawPart( QPointF origin, double rotation, HAlignment alignment, const QgsTextDocument &document,
318 : : QgsRenderContext &context, const QgsTextFormat &format,
319 : : TextPart part );
320 : :
321 : : static double drawBuffer( QgsRenderContext &context,
322 : : const Component &component,
323 : : const QgsTextFormat &format );
324 : :
325 : : static void drawBackground( QgsRenderContext &context,
326 : : Component component,
327 : : const QgsTextFormat &format,
328 : : const QgsTextDocument &document,
329 : : DrawMode mode = Rect );
330 : :
331 : : static void drawShadow( QgsRenderContext &context,
332 : : const Component &component,
333 : : const QgsTextFormat &format );
334 : :
335 : : static void drawMask( QgsRenderContext &context,
336 : : const Component &component,
337 : : const QgsTextFormat &format );
338 : :
339 : : static void drawText( QgsRenderContext &context,
340 : : const Component &component,
341 : : const QgsTextFormat &format );
342 : :
343 : : static void drawTextInternal( TextPart drawType,
344 : : QgsRenderContext &context,
345 : : const QgsTextFormat &format,
346 : : const Component &component,
347 : : const QgsTextDocument &document,
348 : : const QFontMetricsF *fontMetrics,
349 : : HAlignment alignment,
350 : : VAlignment vAlignment,
351 : : DrawMode mode = Rect );
352 : :
353 : : static QgsTextFormat::TextOrientation calculateRotationAndOrientationForComponent( const QgsTextFormat &format, const Component &component, double &rotation );
354 : :
355 : : static void calculateExtraSpacingForLineJustification( double spaceToDistribute, const QgsTextBlock &block, double &extraWordSpace, double &extraLetterSpace );
356 : : static void applyExtraSpacingForLineJustification( QFont &font, double extraWordSpace, double extraLetterSpace );
357 : :
358 : : static void drawTextInternalHorizontal( QgsRenderContext &context,
359 : : const QgsTextFormat &format,
360 : : TextPart drawType,
361 : : DrawMode mode,
362 : : const Component &component,
363 : : const QgsTextDocument &document,
364 : : double fontScale,
365 : : const QFontMetricsF *fontMetrics,
366 : : HAlignment hAlignment,
367 : : VAlignment vAlignment,
368 : : double rotation );
369 : :
370 : : static void drawTextInternalVertical( QgsRenderContext &context,
371 : : const QgsTextFormat &format,
372 : : TextPart drawType,
373 : : DrawMode mode,
374 : : const Component &component,
375 : : const QgsTextDocument &document,
376 : : double fontScale,
377 : : const QFontMetricsF *fontMetrics,
378 : : HAlignment hAlignment,
379 : : VAlignment vAlignment,
380 : : double rotation );
381 : :
382 : : friend class QgsVectorLayerLabelProvider;
383 : : friend class QgsLabelPreview;
384 : :
385 : : static QgsTextFormat updateShadowPosition( const QgsTextFormat &format );
386 : :
387 : : };
388 : :
389 : : #endif // QGSTEXTRENDERER_H
|