2022-05-13 13:12:05 +00:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
#ifndef QQUICKTEXTEDIT_P_P_H
|
|
|
|
#define QQUICKTEXTEDIT_P_P_H
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// W A R N I N G
|
|
|
|
// -------------
|
|
|
|
//
|
|
|
|
// This file is not part of the Qt API. It exists purely as an
|
|
|
|
// implementation detail. This header file may change from version to
|
|
|
|
// version without notice, or even be removed.
|
|
|
|
//
|
|
|
|
// We mean it.
|
|
|
|
//
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
#include "qquicktextedit_p.h"
|
|
|
|
#include "qquickimplicitsizeitem_p_p.h"
|
2017-07-24 13:15:18 +00:00
|
|
|
#include "qquicktextutil_p.h"
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
#include <QtQml/qqml.h>
|
2013-03-18 15:25:59 +00:00
|
|
|
#include <QtCore/qlist.h>
|
2015-06-08 23:35:49 +00:00
|
|
|
#include <private/qlazilyallocated_p.h>
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2016-07-05 14:27:22 +00:00
|
|
|
#include <limits>
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
class QTextLayout;
|
2011-12-05 01:36:55 +00:00
|
|
|
class QQuickTextDocumentWithImageResources;
|
2011-11-10 04:58:17 +00:00
|
|
|
class QQuickTextControl;
|
2013-03-18 15:25:59 +00:00
|
|
|
class QQuickTextNode;
|
2015-06-01 16:03:04 +00:00
|
|
|
class QQuickTextNodeEngine;
|
2014-08-08 18:29:19 +00:00
|
|
|
|
2015-06-18 19:38:57 +00:00
|
|
|
class Q_QUICK_PRIVATE_EXPORT QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2012-05-04 06:07:32 +00:00
|
|
|
public:
|
2011-10-14 08:51:42 +00:00
|
|
|
Q_DECLARE_PUBLIC(QQuickTextEdit)
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2012-05-04 06:07:32 +00:00
|
|
|
typedef QQuickTextEdit Public;
|
|
|
|
|
2013-03-18 15:25:59 +00:00
|
|
|
struct Node {
|
2016-07-05 14:27:22 +00:00
|
|
|
explicit Node(int startPos = std::numeric_limits<int>::max(),
|
|
|
|
QQuickTextNode *node = nullptr)
|
2013-03-18 15:25:59 +00:00
|
|
|
: m_startPos(startPos), m_node(node), m_dirty(false) { }
|
|
|
|
QQuickTextNode* textNode() const { return m_node; }
|
|
|
|
void moveStartPos(int delta) { Q_ASSERT(m_startPos + delta > 0); m_startPos += delta; }
|
|
|
|
int startPos() const { return m_startPos; }
|
|
|
|
void setDirty() { m_dirty = true; }
|
|
|
|
bool dirty() const { return m_dirty; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
int m_startPos;
|
|
|
|
QQuickTextNode* m_node;
|
|
|
|
bool m_dirty;
|
|
|
|
};
|
2016-07-05 14:27:22 +00:00
|
|
|
typedef QList<Node>::iterator TextNodeIterator;
|
2013-03-18 15:25:59 +00:00
|
|
|
|
2015-06-08 23:35:49 +00:00
|
|
|
struct ExtraData {
|
|
|
|
ExtraData();
|
|
|
|
|
|
|
|
qreal padding;
|
|
|
|
qreal topPadding;
|
|
|
|
qreal leftPadding;
|
|
|
|
qreal rightPadding;
|
|
|
|
qreal bottomPadding;
|
|
|
|
bool explicitTopPadding : 1;
|
|
|
|
bool explicitLeftPadding : 1;
|
|
|
|
bool explicitRightPadding : 1;
|
|
|
|
bool explicitBottomPadding : 1;
|
2015-10-03 12:03:57 +00:00
|
|
|
bool implicitResize : 1;
|
2015-06-08 23:35:49 +00:00
|
|
|
};
|
|
|
|
QLazilyAllocated<ExtraData> extra;
|
|
|
|
|
2013-03-18 15:25:59 +00:00
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickTextEditPrivate()
|
2012-02-21 03:31:19 +00:00
|
|
|
: color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF))
|
2015-06-08 23:35:49 +00:00
|
|
|
, textMargin(0.0), xoff(0), yoff(0)
|
2018-02-21 09:41:54 +00:00
|
|
|
, font(sourceFont), cursorComponent(nullptr), cursorItem(nullptr), document(nullptr), control(nullptr)
|
|
|
|
, quickDocument(nullptr), lastSelectionStart(0), lastSelectionEnd(0), lineCount(0)
|
2012-02-21 03:31:19 +00:00
|
|
|
, hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop)
|
|
|
|
, format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap)
|
2017-07-24 13:15:18 +00:00
|
|
|
, renderType(QQuickTextUtil::textRenderType<QQuickTextEdit>())
|
2012-04-24 13:46:27 +00:00
|
|
|
, contentDirection(Qt::LayoutDirectionAuto)
|
2012-11-22 17:47:45 +00:00
|
|
|
, mouseSelectionMode(QQuickTextEdit::SelectCharacters)
|
2016-11-16 13:22:36 +00:00
|
|
|
#if QT_CONFIG(im)
|
2012-11-22 17:47:45 +00:00
|
|
|
, inputMethodHints(Qt::ImhNone)
|
|
|
|
#endif
|
2012-02-21 03:31:19 +00:00
|
|
|
, updateType(UpdatePaintNode)
|
2013-03-18 15:25:59 +00:00
|
|
|
, dirty(false), richText(false), cursorVisible(false), cursorPending(false)
|
2012-02-21 03:31:19 +00:00
|
|
|
, focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
|
|
|
|
, selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
|
2013-03-01 14:26:54 +00:00
|
|
|
, textCached(true), inLayout(false), selectByKeyboard(false), selectByKeyboardSet(false)
|
2017-12-19 20:45:21 +00:00
|
|
|
, hadSelection(false), markdownText(false)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-01-16 06:40:13 +00:00
|
|
|
static QQuickTextEditPrivate *get(QQuickTextEdit *item) {
|
|
|
|
return static_cast<QQuickTextEditPrivate *>(QObjectPrivate::get(item)); }
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
void init();
|
|
|
|
|
2016-01-13 12:54:15 +00:00
|
|
|
void resetInputMethod();
|
2011-04-27 12:13:26 +00:00
|
|
|
void updateDefaultTextOption();
|
|
|
|
void relayoutDocument();
|
|
|
|
bool determineHorizontalAlignment();
|
2011-10-14 08:51:42 +00:00
|
|
|
bool setHAlign(QQuickTextEdit::HAlignment, bool forceAlign = false);
|
2017-09-20 18:57:39 +00:00
|
|
|
void mirrorChange() override;
|
TextEdit large text: don't populate blocks outside the viewport into SG
When the text is larger than 10000 characters, we now avoid creating
nodes for blocks that go outside the viewport. Each time the text moves
relative to the viewport, we check whether the rectangular area that we
know is "covered" with the text rendered so far is still enough to fill
the viewport; if not, update the whole document: mark all existing SG
nodes dirty, then delete and re-create them.
[ChangeLog][QtQuick][Text] When given large text documents
(QString::size() > 10000), Text and TextEdit now try to avoid populating
scene graph nodes for ranges of text that fall outside the viewport,
which could be a parent item having the ItemIsViewport flag set (such as
a Flickable), or the window's content item. If the viewport is smaller
than the window, you might see lines of text disappearing when they are
scrolled out of the viewport; if that's undesired, either design your UI
so that other items obscure the area beyond the viewport, or set the
clip property to make clipping exact.
Task-number: QTBUG-90734
Change-Id: I9c88885b1ad3c3f24df0f7f322ed82d76b8e07c9
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
2021-10-26 09:50:33 +00:00
|
|
|
bool transformChanged(QQuickItem *transformedItem) override;
|
2017-09-20 18:57:39 +00:00
|
|
|
qreal getImplicitWidth() const override;
|
2012-04-24 13:46:27 +00:00
|
|
|
Qt::LayoutDirection textDirection(const QString &text) const;
|
2013-04-22 16:14:55 +00:00
|
|
|
bool isLinkHoveredConnected();
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2022-06-08 12:51:45 +00:00
|
|
|
#if QT_CONFIG(cursor)
|
|
|
|
void updateMouseCursorShape();
|
|
|
|
#endif
|
|
|
|
|
2014-10-14 08:44:47 +00:00
|
|
|
void setNativeCursorEnabled(bool) {}
|
2013-03-04 20:26:13 +00:00
|
|
|
void handleFocusEvent(QFocusEvent *event);
|
2015-06-01 16:03:04 +00:00
|
|
|
void addCurrentTextNodeToRoot(QQuickTextNodeEngine *, QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos);
|
2013-03-25 18:58:46 +00:00
|
|
|
QQuickTextNode* createTextNode();
|
2012-05-04 06:07:32 +00:00
|
|
|
|
2016-11-16 13:22:36 +00:00
|
|
|
#if QT_CONFIG(im)
|
2013-02-27 11:53:23 +00:00
|
|
|
Qt::InputMethodHints effectiveInputMethodHints() const;
|
|
|
|
#endif
|
|
|
|
|
2015-06-08 23:35:49 +00:00
|
|
|
inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; }
|
2015-02-04 17:00:53 +00:00
|
|
|
void setTopPadding(qreal value, bool reset = false);
|
|
|
|
void setLeftPadding(qreal value, bool reset = false);
|
|
|
|
void setRightPadding(qreal value, bool reset = false);
|
|
|
|
void setBottomPadding(qreal value, bool reset = false);
|
|
|
|
|
2015-10-03 16:23:28 +00:00
|
|
|
bool isImplicitResizeEnabled() const;
|
|
|
|
void setImplicitResizeEnabled(bool enabled);
|
2015-10-03 12:03:57 +00:00
|
|
|
|
2012-02-21 03:31:19 +00:00
|
|
|
QColor color;
|
|
|
|
QColor selectionColor;
|
|
|
|
QColor selectedTextColor;
|
|
|
|
|
2012-02-23 04:11:48 +00:00
|
|
|
QSizeF contentSize;
|
2012-02-21 03:31:19 +00:00
|
|
|
|
|
|
|
qreal textMargin;
|
2012-07-10 01:30:53 +00:00
|
|
|
qreal xoff;
|
2012-02-23 04:11:48 +00:00
|
|
|
qreal yoff;
|
2012-02-21 03:31:19 +00:00
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
QString text;
|
2012-01-17 00:42:26 +00:00
|
|
|
QUrl baseUrl;
|
2011-04-27 12:13:26 +00:00
|
|
|
QFont sourceFont;
|
2012-02-21 03:31:19 +00:00
|
|
|
QFont font;
|
|
|
|
|
2012-03-05 01:39:24 +00:00
|
|
|
QQmlComponent* cursorComponent;
|
2012-05-04 06:07:32 +00:00
|
|
|
QQuickItem* cursorItem;
|
2012-02-21 03:31:19 +00:00
|
|
|
QQuickTextDocumentWithImageResources *document;
|
|
|
|
QQuickTextControl *control;
|
2013-02-15 17:25:47 +00:00
|
|
|
QQuickTextDocument *quickDocument;
|
2016-07-05 14:27:22 +00:00
|
|
|
QList<Node> textNodeMap;
|
2012-02-21 03:31:19 +00:00
|
|
|
|
|
|
|
int lastSelectionStart;
|
|
|
|
int lastSelectionEnd;
|
|
|
|
int lineCount;
|
2021-12-13 07:14:26 +00:00
|
|
|
int firstBlockInViewport = -1; // only for the autotest; can be wrong after scrolling sometimes
|
|
|
|
int firstBlockPastViewport = -1; // only for the autotest
|
TextEdit large text: don't populate blocks outside the viewport into SG
When the text is larger than 10000 characters, we now avoid creating
nodes for blocks that go outside the viewport. Each time the text moves
relative to the viewport, we check whether the rectangular area that we
know is "covered" with the text rendered so far is still enough to fill
the viewport; if not, update the whole document: mark all existing SG
nodes dirty, then delete and re-create them.
[ChangeLog][QtQuick][Text] When given large text documents
(QString::size() > 10000), Text and TextEdit now try to avoid populating
scene graph nodes for ranges of text that fall outside the viewport,
which could be a parent item having the ItemIsViewport flag set (such as
a Flickable), or the window's content item. If the viewport is smaller
than the window, you might see lines of text disappearing when they are
scrolled out of the viewport; if that's undesired, either design your UI
so that other items obscure the area beyond the viewport, or set the
clip property to make clipping exact.
Task-number: QTBUG-90734
Change-Id: I9c88885b1ad3c3f24df0f7f322ed82d76b8e07c9
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
2021-10-26 09:50:33 +00:00
|
|
|
QRectF renderedRegion;
|
2012-02-21 03:31:19 +00:00
|
|
|
|
|
|
|
enum UpdateType {
|
|
|
|
UpdateNone,
|
|
|
|
UpdateOnlyPreprocess,
|
Invalidate text when application fonts are added or removed
We had multiple related issues due to application fonts being added
or removed during the application lifetime.
1. If a text had font family "foo" set, and this font did not
exist at the time, then loading "foo" at a later stage would not
update the text to use the correct font, since the result of
the previous request had been cached.
2. A variation of #1 was if the font "foo" was loaded by a FontLoader
in the scene and referred to by name in the text component. In this
case, there was a race condition, where the font lookup would sometimes
yield different results on the main thread and on the render thread,
and text would be garbled.
3. When a font was removed from the font database, then references to
it would remain in the caches (glyph cache + font cache) in the render
thread. With certain backends (DirectWrite, CoreText) this caused errors
or even crashes, as the cached font engines would be referring to data
that had been removed.
The work-around for #1 and #2 was merely to avoid hardcoding names for
fonts, but instead getting them from the FontLoader. This way, you can
avoid requesting the font family before it is available (and thus avoid
caching the wrong result). However, for #3 there is no known work-around.
This patch fixes all three (together with a smaller patch for qtbase) by
invalidating all text and related caches in Qt Quick when fonts are
either added or removed from the font database. This does add some
overhead if font loading happens during runtime, but the alternative is
broken behavior and dangling pointers.
This is done during the synchronization step. Before synchronization,
the font cache is flushed and all text components are marked for update,
so that fonts are re-requested against the new font database.
After synchronization, we delete all distance field glyph caches which
are not currently in use, to avoid having references to stale application
font data in the list.
[ChangeLog][Text] Fix multiple issues with usage of application fonts when
they are added or removed during the lifetime of the application.
Task-number: QTBUG-100697
Task-number: QDS-1142
Change-Id: Ib309e54e0ee97b6be6d2a7211964043fd51c9ec5
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-03-18 11:57:01 +00:00
|
|
|
UpdatePaintNode,
|
|
|
|
UpdateAll
|
2012-02-21 03:31:19 +00:00
|
|
|
};
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
QQuickTextEdit::HAlignment hAlign;
|
|
|
|
QQuickTextEdit::VAlignment vAlign;
|
2012-02-21 03:31:19 +00:00
|
|
|
QQuickTextEdit::TextFormat format;
|
|
|
|
QQuickTextEdit::WrapMode wrapMode;
|
2012-07-04 12:56:38 +00:00
|
|
|
QQuickTextEdit::RenderType renderType;
|
2012-04-24 13:46:27 +00:00
|
|
|
Qt::LayoutDirection contentDirection;
|
2012-02-21 03:31:19 +00:00
|
|
|
QQuickTextEdit::SelectionMode mouseSelectionMode;
|
2016-11-16 13:22:36 +00:00
|
|
|
#if QT_CONFIG(im)
|
2012-02-21 03:31:19 +00:00
|
|
|
Qt::InputMethodHints inputMethodHints;
|
2012-11-22 17:47:45 +00:00
|
|
|
#endif
|
2012-02-21 03:31:19 +00:00
|
|
|
UpdateType updateType;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
bool dirty : 1;
|
|
|
|
bool richText : 1;
|
|
|
|
bool cursorVisible : 1;
|
2012-05-04 06:07:32 +00:00
|
|
|
bool cursorPending : 1;
|
2011-04-27 12:13:26 +00:00
|
|
|
bool focusOnPress : 1;
|
|
|
|
bool persistentSelection : 1;
|
|
|
|
bool requireImplicitWidth:1;
|
|
|
|
bool selectByMouse:1;
|
|
|
|
bool canPaste:1;
|
2011-12-20 07:21:55 +00:00
|
|
|
bool canPasteValid:1;
|
2011-04-27 12:13:26 +00:00
|
|
|
bool hAlignImplicit:1;
|
2012-01-11 01:00:36 +00:00
|
|
|
bool textCached:1;
|
2012-03-22 02:04:16 +00:00
|
|
|
bool inLayout:1;
|
2013-03-01 14:26:54 +00:00
|
|
|
bool selectByKeyboard:1;
|
|
|
|
bool selectByKeyboardSet:1;
|
2013-03-18 15:25:59 +00:00
|
|
|
bool hadSelection : 1;
|
2017-12-19 20:45:21 +00:00
|
|
|
bool markdownText : 1;
|
TextEdit large text: don't populate blocks outside the viewport into SG
When the text is larger than 10000 characters, we now avoid creating
nodes for blocks that go outside the viewport. Each time the text moves
relative to the viewport, we check whether the rectangular area that we
know is "covered" with the text rendered so far is still enough to fill
the viewport; if not, update the whole document: mark all existing SG
nodes dirty, then delete and re-create them.
[ChangeLog][QtQuick][Text] When given large text documents
(QString::size() > 10000), Text and TextEdit now try to avoid populating
scene graph nodes for ranges of text that fall outside the viewport,
which could be a parent item having the ItemIsViewport flag set (such as
a Flickable), or the window's content item. If the viewport is smaller
than the window, you might see lines of text disappearing when they are
scrolled out of the viewport; if that's undesired, either design your UI
so that other items obscure the area beyond the viewport, or set the
clip property to make clipping exact.
Task-number: QTBUG-90734
Change-Id: I9c88885b1ad3c3f24df0f7f322ed82d76b8e07c9
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
2021-10-26 09:50:33 +00:00
|
|
|
|
|
|
|
static const int largeTextSizeThreshold;
|
2011-04-27 12:13:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
2011-10-14 08:51:42 +00:00
|
|
|
#endif // QQUICKTEXTEDIT_P_P_H
|