1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <qabstracttextdocumentlayout.h>
41 #include <qtextformat.h>
42 #include "qtextdocument_p.h"
43 #include "qtextengine_p.h"
44 #include "qtextlist.h"
45 
46 #include "qabstracttextdocumentlayout_p.h"
47 
48 QT_BEGIN_NAMESPACE
49 
~QAbstractTextDocumentLayoutPrivate()50 QAbstractTextDocumentLayoutPrivate::~QAbstractTextDocumentLayoutPrivate()
51 {
52 }
53 
~QTextObjectInterface()54 QTextObjectInterface::~QTextObjectInterface()
55 {
56     // must be empty until ### Qt 6
57 }
58 
59 /*!
60     \class QAbstractTextDocumentLayout
61     \reentrant
62 
63     \brief The QAbstractTextDocumentLayout class is an abstract base
64     class used to implement custom layouts for QTextDocuments.
65     \inmodule QtGui
66 
67     \ingroup richtext-processing
68 
69     The standard layout provided by Qt can handle simple word processing
70     including inline images, lists and tables.
71 
72     Some applications, e.g., a word processor or a DTP application might need
73     more features than the ones provided by Qt's layout engine, in which case
74     you can subclass QAbstractTextDocumentLayout to provide custom layout
75     behavior for your text documents.
76 
77     An instance of the QAbstractTextDocumentLayout subclass can be installed
78     on a QTextDocument object with the
79     \l{QTextDocument::}{setDocumentLayout()} function.
80 
81     You can insert custom objects into a QTextDocument; see the
82     QTextObjectInterface class description for details.
83 
84     \sa QTextObjectInterface
85 */
86 
87 /*!
88     \class QTextObjectInterface
89     \brief The QTextObjectInterface class allows drawing of
90            custom text objects in \l{QTextDocument}s.
91     \since 4.5
92     \inmodule QtGui
93 
94     A text object describes the structure of one or more elements in a
95     text document; for instance, images imported from HTML are
96     implemented using text objects. A text object knows how to lay out
97     and draw its elements when a document is being rendered.
98 
99     Qt allows custom text objects to be inserted into a document by
100     registering a custom \l{QTextCharFormat::objectType()}{object
101     type} with QTextCharFormat. A QTextObjectInterface must also be
102     implemented for this type and be
103     \l{QAbstractTextDocumentLayout::registerHandler()}{registered}
104     with the QAbstractTextDocumentLayout of the document. When the
105     object type is encountered while rendering a QTextDocument, the
106     intrinsicSize() and drawObject() functions of the interface are
107     called.
108 
109     The following list explains the required steps of inserting a
110     custom text object into a document:
111 
112     \list
113         \li Choose an \a objectType. The \a objectType is an integer with a
114             value greater or equal to QTextFormat::UserObject.
115          \li Create a QTextCharFormat object and set the object type to the
116             chosen type using the setObjectType() function.
117          \li Implement the QTextObjectInterface class.
118          \li Call QAbstractTextDocumentLayout::registerHandler() with an instance of your
119             QTextObjectInterface subclass to register your object type.
120          \li Insert QChar::ObjectReplacementCharacter with the aforementioned
121             QTextCharFormat of the chosen object type into the document.
122             As mentioned, the functions of QTextObjectInterface
123             \l{QTextObjectInterface::}{intrinsicSize()} and
124             \l{QTextObjectInterface::}{drawObject()} will then be called with the
125             QTextFormat as parameter whenever the replacement character is
126             encountered.
127     \endlist
128 
129     A class implementing a text object needs to inherit both QObject
130     and QTextObjectInterface. QObject must be the first class
131     inherited. For instance:
132 
133     \snippet qtextobject/textobjectinterface.h 0
134 
135     The data of a text object is usually stored in the QTextCharFormat
136     using QTextCharFormat::setProperty(), and then retrieved with
137     QTextCharFormat::property().
138 
139     \warning Copy and Paste operations ignore custom text objects.
140 
141     \sa {Text Object Example}, QTextCharFormat, QTextLayout
142 */
143 
144 /*!
145     \fn QTextObjectInterface::~QTextObjectInterface()
146 
147     Destroys this QTextObjectInterface.
148 */
149 
150 /*!
151     \fn virtual QSizeF QTextObjectInterface::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
152 
153     The intrinsicSize() function returns the size of the text object
154     represented by \a format in the given document (\a doc) at the
155     given position (\a posInDocument).
156 
157     The size calculated will be used for subsequent calls to
158     drawObject() for this \a format.
159 
160     \sa drawObject()
161 */
162 
163 /*!
164     \fn virtual void QTextObjectInterface::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
165 
166     Draws this text object using the specified \a painter.
167 
168     The size of the rectangle, \a rect, to draw in is the size
169     previously calculated by intrinsicSize(). The rectangles position
170     is relative to the \a painter.
171 
172     You also get the document (\a doc) and the position (\a
173     posInDocument) of the \a format in that document.
174 
175     \sa intrinsicSize()
176 */
177 
178 /*!
179     \fn void QAbstractTextDocumentLayout::update(const QRectF &rect)
180 
181     This signal is emitted when the rectangle \a rect has been updated.
182 
183     Subclasses of QAbstractTextDocumentLayout should emit this signal when
184     the layout of the contents change in order to repaint.
185 */
186 
187 /*!
188    \fn void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
189    \since 4.4
190 
191    This signal is emitted when the specified \a block has been updated.
192 
193    Subclasses of QAbstractTextDocumentLayout should emit this signal when
194    the layout of \a block has changed in order to repaint.
195 */
196 
197 /*!
198     \fn void QAbstractTextDocumentLayout::documentSizeChanged(const QSizeF &newSize)
199 
200     This signal is emitted when the size of the document layout changes to
201     \a newSize.
202 
203     Subclasses of QAbstractTextDocumentLayout should emit this signal when the
204     document's entire layout size changes. This signal is useful for widgets
205     that display text documents since it enables them to update their scroll
206     bars correctly.
207 
208     \sa documentSize()
209 */
210 
211 /*!
212     \fn void QAbstractTextDocumentLayout::pageCountChanged(int newPages)
213 
214     This signal is emitted when the number of pages in the layout changes;
215     \a newPages is the updated page count.
216 
217     Subclasses of QAbstractTextDocumentLayout should emit this signal when
218     the number of pages in the layout has changed. Changes to the page count
219     are caused by changes to the layout or the document content itself.
220 
221     \sa pageCount()
222 */
223 
224 /*!
225     \fn int QAbstractTextDocumentLayout::pageCount() const
226 
227     Returns the number of pages contained in the layout.
228 
229     \sa pageCountChanged()
230 */
231 
232 /*!
233     \fn QSizeF QAbstractTextDocumentLayout::documentSize() const
234 
235     Returns the total size of the document's layout.
236 
237     This information can be used by display widgets to update their scroll bars
238     correctly.
239 
240     \sa documentSizeChanged(), QTextDocument::pageSize
241 */
242 
243 /*!
244     \fn void QAbstractTextDocumentLayout::draw(QPainter *painter, const PaintContext &context)
245 
246     Draws the layout with the given \a painter using the given \a context.
247 */
248 
249 /*!
250     \fn int QAbstractTextDocumentLayout::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
251 
252     Returns the cursor position for the given \a point with the specified
253     \a accuracy. Returns -1 if no valid cursor position was found.
254 */
255 
256 /*!
257     \fn void QAbstractTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
258 
259     This function is called whenever the contents of the document change. A
260     change occurs when text is inserted, removed, or a combination of these
261     two. The change is specified by \a position, \a charsRemoved, and
262     \a charsAdded corresponding to the starting character position of the
263     change, the number of characters removed from the document, and the
264     number of characters added.
265 
266     For example, when inserting the text "Hello" into an empty document,
267     \a charsRemoved would be 0 and \a charsAdded would be 5 (the length of
268     the string).
269 
270     Replacing text is a combination of removing and inserting. For example, if
271     the text "Hello" gets replaced by "Hi", \a charsRemoved would be 5 and
272     \a charsAdded would be 2.
273 
274     For subclasses of QAbstractTextDocumentLayout, this is the central function
275     where a large portion of the work to lay out and position document contents
276     is done.
277 
278     For example, in a subclass that only arranges blocks of text, an
279     implementation of this function would have to do the following:
280 
281     \list
282         \li Determine the list of changed \l{QTextBlock}(s) using the parameters
283             provided.
284         \li Each QTextBlock object's corresponding QTextLayout object needs to
285             be processed. You can access the \l{QTextBlock}'s layout using the
286             QTextBlock::layout() function. This processing should take the
287             document's page size into consideration.
288         \li If the total number of pages changed, the pageCountChanged() signal
289             should be emitted.
290         \li If the total size changed, the documentSizeChanged() signal should
291             be emitted.
292         \li The update() signal should be emitted to schedule a repaint of areas
293             in the layout that require repainting.
294     \endlist
295 
296     \sa QTextLayout
297 */
298 
299 /*!
300     \class QAbstractTextDocumentLayout::PaintContext
301     \reentrant
302     \inmodule QtGui
303 
304     \brief The QAbstractTextDocumentLayout::PaintContext class is a convenience
305     class defining the parameters used when painting a document's layout.
306 
307     A paint context is used when rendering custom layouts for QTextDocuments
308     with the QAbstractTextDocumentLayout::draw() function. It is specified by
309     a \l {cursorPosition}{cursor position}, \l {palette}{default text color},
310     \l clip rectangle and a collection of \l selections.
311 
312     \sa QAbstractTextDocumentLayout
313 */
314 
315 /*!
316     \fn QAbstractTextDocumentLayout::PaintContext::PaintContext()
317     \internal
318 */
319 
320 /*!
321     \variable QAbstractTextDocumentLayout::PaintContext::cursorPosition
322 
323     \brief the position within the document, where the cursor line should be
324     drawn.
325 
326     The default value is -1.
327 */
328 
329 /*!
330     \variable QAbstractTextDocumentLayout::PaintContext::palette
331 
332     \brief the default color that is used for the text, when no color is
333     specified.
334 
335     The default value is the application's default palette.
336 */
337 
338 /*!
339     \variable QAbstractTextDocumentLayout::PaintContext::clip
340 
341     \brief a hint to the layout specifying the area around paragraphs, frames
342     or text require painting.
343 
344     Everything outside of this rectangle does not need to be painted.
345 
346     Specifying a clip rectangle can speed up drawing of large documents
347     significantly. Note that the clip rectangle is in document coordinates (not
348     in viewport coordinates). It is not a substitute for a clip region set on
349     the painter but merely a hint.
350 
351     The default value is a null rectangle indicating everything needs to be
352     painted.
353 */
354 
355 /*!
356     \variable QAbstractTextDocumentLayout::PaintContext::selections
357 
358     \brief the collection of selections that will be rendered when passing this
359     paint context to QAbstractTextDocumentLayout's draw() function.
360 
361     The default value is an empty vector indicating no selection.
362 */
363 
364 /*!
365     \class QAbstractTextDocumentLayout::Selection
366     \reentrant
367     \inmodule QtGui
368 
369     \brief The QAbstractTextDocumentLayout::Selection class is a convenience
370     class defining the parameters of a selection.
371 
372     A selection can be used to specify a part of a document that should be
373     highlighted when drawing custom layouts for QTextDocuments with the
374     QAbstractTextDocumentLayout::draw() function. It is specified using
375     \l cursor and a \l format.
376 
377     \sa QAbstractTextDocumentLayout, PaintContext
378 */
379 
380 /*!
381     \variable QAbstractTextDocumentLayout::Selection::format
382 
383     \brief the format of the selection
384 
385     The default value is QTextFormat::InvalidFormat.
386 */
387 
388 /*!
389     \variable QAbstractTextDocumentLayout::Selection::cursor
390     \brief the selection's cursor
391 
392     The default value is a null cursor.
393 */
394 
395 /*!
396     Creates a new text document layout for the given \a document.
397 */
QAbstractTextDocumentLayout(QTextDocument * document)398 QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QTextDocument *document)
399     : QObject(*new QAbstractTextDocumentLayoutPrivate, document)
400 {
401     Q_D(QAbstractTextDocumentLayout);
402     d->setDocument(document);
403 }
404 
405 /*!
406     \internal
407 */
QAbstractTextDocumentLayout(QAbstractTextDocumentLayoutPrivate & p,QTextDocument * document)408 QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QAbstractTextDocumentLayoutPrivate &p, QTextDocument *document)
409     :QObject(p, document)
410 {
411     Q_D(QAbstractTextDocumentLayout);
412     d->setDocument(document);
413 }
414 
415 /*!
416     \internal
417 */
~QAbstractTextDocumentLayout()418 QAbstractTextDocumentLayout::~QAbstractTextDocumentLayout()
419 {
420 }
421 
422 /*!
423     Registers the given \a component as a handler for items of the given \a objectType.
424 
425     \note registerHandler() has to be called once for each object type. This
426     means that there is only one handler for multiple replacement characters
427     of the same object type.
428 
429     The text document layout does not take ownership of \c component.
430 */
registerHandler(int objectType,QObject * component)431 void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *component)
432 {
433     Q_D(QAbstractTextDocumentLayout);
434 
435     QTextObjectInterface *iface = qobject_cast<QTextObjectInterface *>(component);
436     if (!iface)
437         return; // ### print error message on terminal?
438 
439     connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
440 
441     QTextObjectHandler h;
442     h.iface = iface;
443     h.component = component;
444     d->handlers.insert(objectType, h);
445 }
446 
447 /*!
448     \since 5.2
449 
450     Unregisters the given \a component as a handler for items of the given \a objectType, or
451     any handler if the \a component is not specified.
452 */
unregisterHandler(int objectType,QObject * component)453 void QAbstractTextDocumentLayout::unregisterHandler(int objectType, QObject *component)
454 {
455     Q_D(QAbstractTextDocumentLayout);
456 
457     const auto it = d->handlers.constFind(objectType);
458     if (it != d->handlers.cend() && (!component || component == it->component)) {
459         if (component)
460             disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
461         d->handlers.erase(it);
462     }
463 }
464 
465 /*!
466     Returns a handler for objects of the given \a objectType.
467 */
handlerForObject(int objectType) const468 QTextObjectInterface *QAbstractTextDocumentLayout::handlerForObject(int objectType) const
469 {
470     Q_D(const QAbstractTextDocumentLayout);
471 
472     QTextObjectHandler handler = d->handlers.value(objectType);
473     if (!handler.component)
474         return nullptr;
475 
476     return handler.iface;
477 }
478 
479 /*!
480     Sets the size of the inline object \a item corresponding to the text
481     \a format.
482 
483     \a posInDocument specifies the position of the object within the document.
484 
485     The default implementation resizes the \a item to the size returned by
486     the object handler's intrinsicSize() function. This function is called only
487     within Qt. Subclasses can reimplement this function to customize the
488     resizing of inline objects.
489 */
resizeInlineObject(QTextInlineObject item,int posInDocument,const QTextFormat & format)490 void QAbstractTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
491 {
492     Q_D(QAbstractTextDocumentLayout);
493 
494     QTextCharFormat f = format.toCharFormat();
495     Q_ASSERT(f.isValid());
496     QTextObjectHandler handler = d->handlers.value(f.objectType());
497     if (!handler.component)
498         return;
499 
500     QSizeF s = handler.iface->intrinsicSize(document(), posInDocument, format);
501     item.setWidth(s.width());
502     item.setAscent(s.height());
503     item.setDescent(0);
504 }
505 
506 /*!
507     Lays out the inline object \a item using the given text \a format.
508 
509     \a posInDocument specifies the position of the object within the document.
510 
511     The default implementation does nothing. This function is called only
512     within Qt. Subclasses can reimplement this function to customize the
513     position of inline objects.
514 
515     \sa drawInlineObject()
516 */
positionInlineObject(QTextInlineObject item,int posInDocument,const QTextFormat & format)517 void QAbstractTextDocumentLayout::positionInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
518 {
519     Q_UNUSED(item);
520     Q_UNUSED(posInDocument);
521     Q_UNUSED(format);
522 }
523 
524 /*!
525     \fn void QAbstractTextDocumentLayout::drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextFormat &format)
526 
527     This function is called to draw the inline object, \a object, with the
528     given \a painter within the rectangle specified by \a rect using the
529     specified text \a format.
530 
531     \a posInDocument specifies the position of the object within the document.
532 
533     The default implementation calls drawObject() on the object handlers. This
534     function is called only within Qt. Subclasses can reimplement this function
535     to customize the drawing of inline objects.
536 
537     \sa draw()
538 */
drawInlineObject(QPainter * p,const QRectF & rect,QTextInlineObject item,int posInDocument,const QTextFormat & format)539 void QAbstractTextDocumentLayout::drawInlineObject(QPainter *p, const QRectF &rect, QTextInlineObject item,
540                                                    int posInDocument, const QTextFormat &format)
541 {
542     Q_UNUSED(item);
543     Q_D(QAbstractTextDocumentLayout);
544 
545     QTextCharFormat f = format.toCharFormat();
546     Q_ASSERT(f.isValid());
547     QTextObjectHandler handler = d->handlers.value(f.objectType());
548     if (!handler.component)
549         return;
550 
551     handler.iface->drawObject(p, rect, document(), posInDocument, format);
552 }
553 
_q_handlerDestroyed(QObject * obj)554 void QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed(QObject *obj)
555 {
556     HandlerHash::Iterator it = handlers.begin();
557     while (it != handlers.end())
558         if ((*it).component == obj)
559             it = handlers.erase(it);
560         else
561             ++it;
562 }
563 
564 /*!
565     \internal
566 
567     Returns the index of the format at position \a pos.
568 */
formatIndex(int pos)569 int QAbstractTextDocumentLayout::formatIndex(int pos)
570 {
571     QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
572     return pieceTable->find(pos).value()->format;
573 }
574 
575 /*!
576     \fn QTextCharFormat QAbstractTextDocumentLayout::format(int position)
577 
578     Returns the character format that is applicable at the given \a position.
579 */
format(int pos)580 QTextCharFormat QAbstractTextDocumentLayout::format(int pos)
581 {
582     QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
583     int idx = pieceTable->find(pos).value()->format;
584     return pieceTable->formatCollection()->charFormat(idx);
585 }
586 
587 
588 
589 /*!
590     Returns the text document that this layout is operating on.
591 */
document() const592 QTextDocument *QAbstractTextDocumentLayout::document() const
593 {
594     Q_D(const QAbstractTextDocumentLayout);
595     return d->document;
596 }
597 
598 /*!
599     \fn QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const
600 
601     Returns the reference of the anchor the given \a position, or an empty
602     string if no anchor exists at that point.
603 */
anchorAt(const QPointF & pos) const604 QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const
605 {
606     QTextCharFormat fmt = formatAt(pos).toCharFormat();
607     return fmt.anchorHref();
608 }
609 
610 /*!
611     \since 5.8
612 
613     Returns the source of the image at the given position \a pos, or an empty
614     string if no image exists at that point.
615 */
imageAt(const QPointF & pos) const616 QString QAbstractTextDocumentLayout::imageAt(const QPointF &pos) const
617 {
618     QTextImageFormat fmt = formatAt(pos).toImageFormat();
619     return fmt.name();
620 }
621 
622 /*!
623     \since 5.8
624 
625     Returns the text format at the given position \a pos.
626 */
formatAt(const QPointF & pos) const627 QTextFormat QAbstractTextDocumentLayout::formatAt(const QPointF &pos) const
628 {
629     int cursorPos = hitTest(pos, Qt::ExactHit);
630     if (cursorPos == -1)
631         return QTextFormat();
632 
633     // compensate for preedit in the hit text block
634     QTextBlock block = document()->firstBlock();
635     while (block.isValid()) {
636         QRectF blockBr = blockBoundingRect(block);
637         if (blockBr.contains(pos)) {
638             QTextLayout *layout = block.layout();
639             int relativeCursorPos = cursorPos - block.position();
640             const int preeditLength = layout ? layout->preeditAreaText().length() : 0;
641             if (preeditLength > 0 && relativeCursorPos > layout->preeditAreaPosition())
642                 cursorPos -= qMin(cursorPos - layout->preeditAreaPosition(), preeditLength);
643             break;
644         }
645         block = block.next();
646     }
647 
648     QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle();
649     QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos);
650     return pieceTable->formatCollection()->format(it->format);
651 }
652 
653 /*!
654     \since 5.14
655 
656     Returns the block (probably a list item) whose \l{QTextBlockFormat::marker()}{marker}
657     is found at the given position \a pos.
658 */
blockWithMarkerAt(const QPointF & pos) const659 QTextBlock QAbstractTextDocumentLayout::blockWithMarkerAt(const QPointF &pos) const
660 {
661     QTextBlock block = document()->firstBlock();
662     while (block.isValid()) {
663         if (block.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker) {
664             QRectF blockBr = blockBoundingRect(block);
665             QTextBlockFormat blockFmt = block.blockFormat();
666             QFontMetrics fm(block.charFormat().font());
667             qreal totalIndent = blockFmt.indent() + blockFmt.leftMargin() + blockFmt.textIndent();
668             if (block.textList())
669                 totalIndent += block.textList()->format().indent() * 40;
670             QRectF adjustedBr = blockBr.adjusted(totalIndent - fm.height(), 0, totalIndent - blockBr.width(), fm.height() - blockBr.height());
671             if (adjustedBr.contains(pos)) {
672                 //qDebug() << "hit block" << block.text() << blockBr << adjustedBr << "marker" << block.blockFormat().marker()
673                 //         << "font" << block.charFormat().font() << "adj" << lineHeight << totalIndent;
674                 if (block.blockFormat().hasProperty(QTextFormat::BlockMarker))
675                     return block;
676             }
677         }
678         block = block.next();
679     }
680     return QTextBlock();
681 }
682 
683 /*!
684     \fn QRectF QAbstractTextDocumentLayout::frameBoundingRect(QTextFrame *frame) const
685 
686     Returns the bounding rectangle of \a frame.
687 */
688 
689 /*!
690     \fn QRectF QAbstractTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
691 
692     Returns the bounding rectangle of \a block.
693 */
694 
695 /*!
696     Sets the paint device used for rendering the document's layout to the given
697     \a device.
698 
699     \sa paintDevice()
700 */
setPaintDevice(QPaintDevice * device)701 void QAbstractTextDocumentLayout::setPaintDevice(QPaintDevice *device)
702 {
703     Q_D(QAbstractTextDocumentLayout);
704     d->paintDevice = device;
705 }
706 
707 /*!
708     Returns the paint device used to render the document's layout.
709 
710     \sa setPaintDevice()
711 */
paintDevice() const712 QPaintDevice *QAbstractTextDocumentLayout::paintDevice() const
713 {
714     Q_D(const QAbstractTextDocumentLayout);
715     return d->paintDevice;
716 }
717 
718 QT_END_NAMESPACE
719 
720 #include "moc_qabstracttextdocumentlayout.cpp"
721