diff --git a/Telegram/private/qcssparser_p.h b/Telegram/private/qcssparser_p.h new file mode 100644 index 000000000..4da7b62db --- /dev/null +++ b/Telegram/private/qcssparser_p.h @@ -0,0 +1,870 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCSSPARSER_P_H +#define QCSSPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QIcon; +QT_END_NAMESPACE + +#ifndef QT_NO_CSSPARSER + +// VxWorks defines NONE as (-1) "for times when NULL won't do" +#if defined(Q_OS_VXWORKS) && defined(NONE) +# undef NONE +#endif +#if defined(Q_OS_INTEGRITY) +# undef Value +#endif + +#define QT_CSS_DECLARE_TYPEINFO(Class, Type) \ + } /* namespace QCss */ \ + Q_DECLARE_TYPEINFO(QCss:: Class, Type); \ + namespace QCss { + +QT_BEGIN_NAMESPACE + +namespace QCss +{ + +enum Property { + UnknownProperty, + BackgroundColor, + Color, + Float, + Font, + FontFamily, + FontSize, + FontStyle, + FontWeight, + Margin, + MarginBottom, + MarginLeft, + MarginRight, + MarginTop, + QtBlockIndent, + QtListIndent, + QtParagraphType, + QtTableType, + QtUserState, + TextDecoration, + TextIndent, + TextUnderlineStyle, + VerticalAlignment, + Whitespace, + QtSelectionForeground, + QtSelectionBackground, + Border, + BorderLeft, + BorderRight, + BorderTop, + BorderBottom, + Padding, + PaddingLeft, + PaddingRight, + PaddingTop, + PaddingBottom, + PageBreakBefore, + PageBreakAfter, + QtAlternateBackground, + BorderLeftStyle, + BorderRightStyle, + BorderTopStyle, + BorderBottomStyle, + BorderStyles, + BorderLeftColor, + BorderRightColor, + BorderTopColor, + BorderBottomColor, + BorderColor, + BorderLeftWidth, + BorderRightWidth, + BorderTopWidth, + BorderBottomWidth, + BorderWidth, + BorderTopLeftRadius, + BorderTopRightRadius, + BorderBottomLeftRadius, + BorderBottomRightRadius, + BorderRadius, + Background, + BackgroundOrigin, + BackgroundClip, + BackgroundRepeat, + BackgroundPosition, + BackgroundAttachment, + BackgroundImage, + BorderImage, + QtSpacing, + Width, + Height, + MinimumWidth, + MinimumHeight, + MaximumWidth, + MaximumHeight, + QtImage, + Left, + Right, + Top, + Bottom, + QtOrigin, + QtPosition, + Position, + QtStyleFeatures, + QtBackgroundRole, + ListStyleType, + ListStyle, + QtImageAlignment, + TextAlignment, + Outline, + OutlineOffset, + OutlineWidth, + OutlineColor, + OutlineStyle, + OutlineRadius, + OutlineTopLeftRadius, + OutlineTopRightRadius, + OutlineBottomLeftRadius, + OutlineBottomRightRadius, + FontVariant, + TextTransform, + QtListNumberPrefix, + QtListNumberSuffix, + LineHeight, + QtLineHeightType, + NumProperties +}; + +enum KnownValue { + UnknownValue, + Value_Normal, + Value_Pre, + Value_NoWrap, + Value_PreWrap, + Value_Small, + Value_Medium, + Value_Large, + Value_XLarge, + Value_XXLarge, + Value_Italic, + Value_Oblique, + Value_Bold, + Value_Underline, + Value_Overline, + Value_LineThrough, + Value_Sub, + Value_Super, + Value_Left, + Value_Right, + Value_Top, + Value_Bottom, + Value_Center, + Value_Native, + Value_Solid, + Value_Dotted, + Value_Dashed, + Value_DotDash, + Value_DotDotDash, + Value_Double, + Value_Groove, + Value_Ridge, + Value_Inset, + Value_Outset, + Value_Wave, + Value_Middle, + Value_Auto, + Value_Always, + Value_None, + Value_Transparent, + Value_Disc, + Value_Circle, + Value_Square, + Value_Decimal, + Value_LowerAlpha, + Value_UpperAlpha, + Value_LowerRoman, + Value_UpperRoman, + Value_SmallCaps, + Value_Uppercase, + Value_Lowercase, + + /* keep these in same order as QPalette::ColorRole */ + Value_FirstColorRole, + Value_WindowText = Value_FirstColorRole, + Value_Button, + Value_Light, + Value_Midlight, + Value_Dark, + Value_Mid, + Value_Text, + Value_BrightText, + Value_ButtonText, + Value_Base, + Value_Window, + Value_Shadow, + Value_Highlight, + Value_HighlightedText, + Value_Link, + Value_LinkVisited, + Value_AlternateBase, + Value_LastColorRole = Value_AlternateBase, + + Value_Disabled, + Value_Active, + Value_Selected, + Value_On, + Value_Off, + + NumKnownValues +}; + +enum BorderStyle { + BorderStyle_Unknown, + BorderStyle_None, + BorderStyle_Dotted, + BorderStyle_Dashed, + BorderStyle_Solid, + BorderStyle_Double, + BorderStyle_DotDash, + BorderStyle_DotDotDash, + BorderStyle_Groove, + BorderStyle_Ridge, + BorderStyle_Inset, + BorderStyle_Outset, + BorderStyle_Native, + NumKnownBorderStyles +}; + +enum Edge { + TopEdge, + RightEdge, + BottomEdge, + LeftEdge, + NumEdges +}; + +enum Corner { + TopLeftCorner, + TopRightCorner, + BottomLeftCorner, + BottomRightCorner +}; + +enum TileMode { + TileMode_Unknown, + TileMode_Round, + TileMode_Stretch, + TileMode_Repeat, + NumKnownTileModes +}; + +enum Repeat { + Repeat_Unknown, + Repeat_None, + Repeat_X, + Repeat_Y, + Repeat_XY, + NumKnownRepeats +}; + +enum Origin { + Origin_Unknown, + Origin_Padding, + Origin_Border, + Origin_Content, + Origin_Margin, + NumKnownOrigins +}; + +enum PositionMode { + PositionMode_Unknown, + PositionMode_Static, + PositionMode_Relative, + PositionMode_Absolute, + PositionMode_Fixed, + NumKnownPositionModes +}; + +enum Attachment { + Attachment_Unknown, + Attachment_Fixed, + Attachment_Scroll, + NumKnownAttachments +}; + +enum StyleFeature { + StyleFeature_None = 0, + StyleFeature_BackgroundColor = 1, + StyleFeature_BackgroundGradient = 2, + NumKnownStyleFeatures = 4 +}; + +struct Value +{ + enum Type { + Unknown, + Number, + Percentage, + Length, + String, + Identifier, + KnownIdentifier, + Uri, + Color, + Function, + TermOperatorSlash, + TermOperatorComma + }; + inline Value() : type(Unknown) { } + Type type; + QVariant variant; + + Q_GUI_EXPORT QString toString() const; +}; +QT_CSS_DECLARE_TYPEINFO(Value, Q_MOVABLE_TYPE) + +struct ColorData { + ColorData() : role(QPalette::NoRole), type(Invalid) {} + ColorData(const QColor &col) : color(col), role(QPalette::NoRole), type(Color) {} + ColorData(QPalette::ColorRole r) : role(r), type(Role) {} + QColor color; + QPalette::ColorRole role; + enum { Invalid, Color, Role} type; +}; +QT_CSS_DECLARE_TYPEINFO(ColorData, Q_MOVABLE_TYPE) + +struct BrushData { + BrushData() : role(QPalette::NoRole), type(Invalid) {} + BrushData(const QBrush &br) : brush(br), role(QPalette::NoRole), type(Brush) {} + BrushData(QPalette::ColorRole r) : role(r), type(Role) {} + QBrush brush; + QPalette::ColorRole role; + enum { Invalid, Brush, Role, DependsOnThePalette } type; +}; +QT_CSS_DECLARE_TYPEINFO(BrushData, Q_MOVABLE_TYPE) + +struct BackgroundData { + BrushData brush; + QString image; + Repeat repeat; + Qt::Alignment alignment; +}; +QT_CSS_DECLARE_TYPEINFO(BackgroundData, Q_MOVABLE_TYPE) + +struct LengthData { + qreal number; + enum { None, Px, Ex, Em } unit; +}; +QT_CSS_DECLARE_TYPEINFO(LengthData, Q_PRIMITIVE_TYPE) + +struct BorderData { + LengthData width; + BorderStyle style; + BrushData color; +}; +QT_CSS_DECLARE_TYPEINFO(BorderData, Q_MOVABLE_TYPE) + + +// 1. StyleRule - x:hover, y:clicked > z:checked { prop1: value1; prop2: value2; } +// 2. QVector - x:hover, y:clicked z:checked +// 3. QVector - y:clicked z:checked +// 4. QVector - { prop1: value1; prop2: value2; } +// 5. Declaration - prop1: value1; + +struct Q_GUI_EXPORT Declaration +{ + struct DeclarationData : public QSharedData + { + inline DeclarationData() : propertyId(UnknownProperty), important(false), inheritable(false) {} + QString property; + Property propertyId; + QVector values; + QVariant parsed; + bool important:1; + bool inheritable:1; + }; + QExplicitlySharedDataPointer d; + inline Declaration() : d(new DeclarationData()) {} + inline bool isEmpty() const { return d->property.isEmpty() && d->propertyId == UnknownProperty; } + + // helper functions + QColor colorValue(const QPalette & = QPalette()) const; + void colorValues(QColor *c, const QPalette & = QPalette()) const; + QBrush brushValue(const QPalette & = QPalette()) const; + void brushValues(QBrush *c, const QPalette & = QPalette()) const; + + BorderStyle styleValue() const; + void styleValues(BorderStyle *s) const; + + Origin originValue() const; + Repeat repeatValue() const; + Qt::Alignment alignmentValue() const; + PositionMode positionValue() const; + Attachment attachmentValue() const; + int styleFeaturesValue() const; + + bool intValue(int *i, const char *unit = 0) const; + bool realValue(qreal *r, const char *unit = 0) const; + + QSize sizeValue() const; + QRect rectValue() const; + QString uriValue() const; + QIcon iconValue() const; + + void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const; +}; +QT_CSS_DECLARE_TYPEINFO(Declaration, Q_MOVABLE_TYPE) + +const quint64 PseudoClass_Unknown = Q_UINT64_C(0x0000000000000000); +const quint64 PseudoClass_Enabled = Q_UINT64_C(0x0000000000000001); +const quint64 PseudoClass_Disabled = Q_UINT64_C(0x0000000000000002); +const quint64 PseudoClass_Pressed = Q_UINT64_C(0x0000000000000004); +const quint64 PseudoClass_Focus = Q_UINT64_C(0x0000000000000008); +const quint64 PseudoClass_Hover = Q_UINT64_C(0x0000000000000010); +const quint64 PseudoClass_Checked = Q_UINT64_C(0x0000000000000020); +const quint64 PseudoClass_Unchecked = Q_UINT64_C(0x0000000000000040); +const quint64 PseudoClass_Indeterminate = Q_UINT64_C(0x0000000000000080); +const quint64 PseudoClass_Unspecified = Q_UINT64_C(0x0000000000000100); +const quint64 PseudoClass_Selected = Q_UINT64_C(0x0000000000000200); +const quint64 PseudoClass_Horizontal = Q_UINT64_C(0x0000000000000400); +const quint64 PseudoClass_Vertical = Q_UINT64_C(0x0000000000000800); +const quint64 PseudoClass_Window = Q_UINT64_C(0x0000000000001000); +const quint64 PseudoClass_Children = Q_UINT64_C(0x0000000000002000); +const quint64 PseudoClass_Sibling = Q_UINT64_C(0x0000000000004000); +const quint64 PseudoClass_Default = Q_UINT64_C(0x0000000000008000); +const quint64 PseudoClass_First = Q_UINT64_C(0x0000000000010000); +const quint64 PseudoClass_Last = Q_UINT64_C(0x0000000000020000); +const quint64 PseudoClass_Middle = Q_UINT64_C(0x0000000000040000); +const quint64 PseudoClass_OnlyOne = Q_UINT64_C(0x0000000000080000); +const quint64 PseudoClass_PreviousSelected = Q_UINT64_C(0x0000000000100000); +const quint64 PseudoClass_NextSelected = Q_UINT64_C(0x0000000000200000); +const quint64 PseudoClass_Flat = Q_UINT64_C(0x0000000000400000); +const quint64 PseudoClass_Left = Q_UINT64_C(0x0000000000800000); +const quint64 PseudoClass_Right = Q_UINT64_C(0x0000000001000000); +const quint64 PseudoClass_Top = Q_UINT64_C(0x0000000002000000); +const quint64 PseudoClass_Bottom = Q_UINT64_C(0x0000000004000000); +const quint64 PseudoClass_Exclusive = Q_UINT64_C(0x0000000008000000); +const quint64 PseudoClass_NonExclusive = Q_UINT64_C(0x0000000010000000); +const quint64 PseudoClass_Frameless = Q_UINT64_C(0x0000000020000000); +const quint64 PseudoClass_ReadOnly = Q_UINT64_C(0x0000000040000000); +const quint64 PseudoClass_Active = Q_UINT64_C(0x0000000080000000); +const quint64 PseudoClass_Closable = Q_UINT64_C(0x0000000100000000); +const quint64 PseudoClass_Movable = Q_UINT64_C(0x0000000200000000); +const quint64 PseudoClass_Floatable = Q_UINT64_C(0x0000000400000000); +const quint64 PseudoClass_Minimized = Q_UINT64_C(0x0000000800000000); +const quint64 PseudoClass_Maximized = Q_UINT64_C(0x0000001000000000); +const quint64 PseudoClass_On = Q_UINT64_C(0x0000002000000000); +const quint64 PseudoClass_Off = Q_UINT64_C(0x0000004000000000); +const quint64 PseudoClass_Editable = Q_UINT64_C(0x0000008000000000); +const quint64 PseudoClass_Item = Q_UINT64_C(0x0000010000000000); +const quint64 PseudoClass_Closed = Q_UINT64_C(0x0000020000000000); +const quint64 PseudoClass_Open = Q_UINT64_C(0x0000040000000000); +const quint64 PseudoClass_EditFocus = Q_UINT64_C(0x0000080000000000); +const quint64 PseudoClass_Alternate = Q_UINT64_C(0x0000100000000000); +// The Any specifier is never generated, but can be used as a wildcard in searches. +const quint64 PseudoClass_Any = Q_UINT64_C(0x0000ffffffffffff); +const int NumPseudos = 45; + +struct Pseudo +{ + Pseudo() : type(0), negated(false) { } + quint64 type; + QString name; + QString function; + bool negated; +}; +QT_CSS_DECLARE_TYPEINFO(Pseudo, Q_MOVABLE_TYPE) + +struct AttributeSelector +{ + enum ValueMatchType { + NoMatch, + MatchEqual, + MatchContains, + MatchBeginsWith + }; + inline AttributeSelector() : valueMatchCriterium(NoMatch) {} + + QString name; + QString value; + ValueMatchType valueMatchCriterium; +}; +QT_CSS_DECLARE_TYPEINFO(AttributeSelector, Q_MOVABLE_TYPE) + +struct BasicSelector +{ + inline BasicSelector() : relationToNext(NoRelation) {} + + enum Relation { + NoRelation, + MatchNextSelectorIfAncestor, + MatchNextSelectorIfParent, + MatchNextSelectorIfPreceeds + }; + + QString elementName; + + QStringList ids; + QVector pseudos; + QVector attributeSelectors; + + Relation relationToNext; +}; +QT_CSS_DECLARE_TYPEINFO(BasicSelector, Q_MOVABLE_TYPE) + +struct Q_GUI_EXPORT Selector +{ + QVector basicSelectors; + int specificity() const; + quint64 pseudoClass(quint64 *negated = 0) const; + QString pseudoElement() const; +}; +QT_CSS_DECLARE_TYPEINFO(Selector, Q_MOVABLE_TYPE) + +struct StyleRule +{ + StyleRule() : order(0) { } + QVector selectors; + QVector declarations; + int order; +}; +QT_CSS_DECLARE_TYPEINFO(StyleRule, Q_MOVABLE_TYPE) + +struct MediaRule +{ + QStringList media; + QVector styleRules; +}; +QT_CSS_DECLARE_TYPEINFO(MediaRule, Q_MOVABLE_TYPE) + +struct PageRule +{ + QString selector; + QVector declarations; +}; +QT_CSS_DECLARE_TYPEINFO(PageRule, Q_MOVABLE_TYPE) + +struct ImportRule +{ + QString href; + QStringList media; +}; +QT_CSS_DECLARE_TYPEINFO(ImportRule, Q_MOVABLE_TYPE) + +enum StyleSheetOrigin { + StyleSheetOrigin_Unspecified, + StyleSheetOrigin_UserAgent, + StyleSheetOrigin_User, + StyleSheetOrigin_Author, + StyleSheetOrigin_Inline +}; + +struct StyleSheet +{ + StyleSheet() : origin(StyleSheetOrigin_Unspecified), depth(0) { } + QVector styleRules; //only contains rules that are not indexed + QVector mediaRules; + QVector pageRules; + QVector importRules; + StyleSheetOrigin origin; + int depth; // applicable only for inline style sheets + QMultiHash nameIndex; + QMultiHash idIndex; + + Q_GUI_EXPORT void buildIndexes(Qt::CaseSensitivity nameCaseSensitivity = Qt::CaseSensitive); +}; +QT_CSS_DECLARE_TYPEINFO(StyleSheet, Q_MOVABLE_TYPE) + + +class Q_GUI_EXPORT StyleSelector +{ +public: + StyleSelector() : nameCaseSensitivity(Qt::CaseSensitive) {} + virtual ~StyleSelector(); + + union NodePtr { + void *ptr; + int id; + }; + + QVector styleRulesForNode(NodePtr node); + QVector declarationsForNode(NodePtr node, const char *extraPseudo = 0); + + virtual bool nodeNameEquals(NodePtr node, const QString& nodeName) const; + virtual QString attribute(NodePtr node, const QString &name) const = 0; + virtual bool hasAttributes(NodePtr node) const = 0; + virtual QStringList nodeIds(NodePtr node) const; + virtual QStringList nodeNames(NodePtr node) const = 0; + virtual bool isNullNode(NodePtr node) const = 0; + virtual NodePtr parentNode(NodePtr node) const = 0; + virtual NodePtr previousSiblingNode(NodePtr node) const = 0; + virtual NodePtr duplicateNode(NodePtr node) const = 0; + virtual void freeNode(NodePtr node) const = 0; + + QVector styleSheets; + QString medium; + Qt::CaseSensitivity nameCaseSensitivity; +private: + void matchRule(NodePtr node, const StyleRule &rules, StyleSheetOrigin origin, + int depth, QMap *weightedRules); + bool selectorMatches(const Selector &rule, NodePtr node); + bool basicSelectorMatches(const BasicSelector &rule, NodePtr node); +}; + +enum TokenType { + NONE, + + S, + + CDO, + CDC, + INCLUDES, + DASHMATCH, + + LBRACE, + PLUS, + GREATER, + COMMA, + + STRING, + INVALID, + + IDENT, + + HASH, + + ATKEYWORD_SYM, + + EXCLAMATION_SYM, + + LENGTH, + + PERCENTAGE, + NUMBER, + + FUNCTION, + + COLON, + SEMICOLON, + RBRACE, + SLASH, + MINUS, + DOT, + STAR, + LBRACKET, + RBRACKET, + EQUAL, + LPAREN, + RPAREN, + OR +}; + +struct Symbol +{ + inline Symbol() : token(NONE), start(0), len(-1) {} + TokenType token; + QString text; + int start, len; + Q_GUI_EXPORT QString lexem() const; +}; +QT_CSS_DECLARE_TYPEINFO(Symbol, Q_MOVABLE_TYPE) + +class Q_GUI_EXPORT Scanner +{ +public: + static QString preprocess(const QString &input, bool *hasEscapeSequences = 0); + static void scan(const QString &preprocessedInput, QVector *symbols); +}; + +class Q_GUI_EXPORT Parser +{ +public: + Parser(); + explicit Parser(const QString &css, bool file = false); + + void init(const QString &css, bool file = false); + bool parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity = Qt::CaseSensitive); + Symbol errorSymbol(); + + bool parseImport(ImportRule *importRule); + bool parseMedia(MediaRule *mediaRule); + bool parseMedium(QStringList *media); + bool parsePage(PageRule *pageRule); + bool parsePseudoPage(QString *selector); + bool parseNextOperator(Value *value); + bool parseCombinator(BasicSelector::Relation *relation); + bool parseProperty(Declaration *decl); + bool parseRuleset(StyleRule *styleRule); + bool parseSelector(Selector *sel); + bool parseSimpleSelector(BasicSelector *basicSel); + bool parseClass(QString *name); + bool parseElementName(QString *name); + bool parseAttrib(AttributeSelector *attr); + bool parsePseudo(Pseudo *pseudo); + bool parseNextDeclaration(Declaration *declaration); + bool parsePrio(Declaration *declaration); + bool parseExpr(QVector *values); + bool parseTerm(Value *value); + bool parseFunction(QString *name, QString *args); + bool parseHexColor(QColor *col); + bool testAndParseUri(QString *uri); + + inline bool testRuleset() { return testSelector(); } + inline bool testSelector() { return testSimpleSelector(); } + inline bool parseNextSelector(Selector *sel) { if (!testSelector()) return recordError(); return parseSelector(sel); } + bool testSimpleSelector(); + inline bool parseNextSimpleSelector(BasicSelector *basicSel) { if (!testSimpleSelector()) return recordError(); return parseSimpleSelector(basicSel); } + inline bool testElementName() { return test(IDENT) || test(STAR); } + inline bool testClass() { return test(DOT); } + inline bool testAttrib() { return test(LBRACKET); } + inline bool testPseudo() { return test(COLON); } + inline bool testMedium() { return test(IDENT); } + inline bool parseNextMedium(QStringList *media) { if (!testMedium()) return recordError(); return parseMedium(media); } + inline bool testPseudoPage() { return test(COLON); } + inline bool testImport() { return testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("import")); } + inline bool testMedia() { return testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("media")); } + inline bool testPage() { return testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("page")); } + inline bool testCombinator() { return test(PLUS) || test(GREATER) || test(S); } + inline bool testProperty() { return test(IDENT); } + bool testTerm(); + inline bool testExpr() { return testTerm(); } + inline bool parseNextExpr(QVector *values) { if (!testExpr()) return recordError(); return parseExpr(values); } + bool testPrio(); + inline bool testHexColor() { return test(HASH); } + inline bool testFunction() { return test(FUNCTION); } + inline bool parseNextFunction(QString *name, QString *args) { if (!testFunction()) return recordError(); return parseFunction(name, args); } + + inline bool lookupElementName() const { return lookup() == IDENT || lookup() == STAR; } + + inline void skipSpace() { while (test(S)) {}; } + + inline bool hasNext() const { return index < symbols.count(); } + inline TokenType next() { return symbols.at(index++).token; } + bool next(TokenType t); + bool test(TokenType t); + inline void prev() { index--; } + inline const Symbol &symbol() const { return symbols.at(index - 1); } + inline QString lexem() const { return symbol().lexem(); } + QString unquotedLexem() const; + QString lexemUntil(TokenType t); + bool until(TokenType target, TokenType target2 = NONE); + inline TokenType lookup() const { + return (index - 1) < symbols.count() ? symbols.at(index - 1).token : NONE; + } + + bool testTokenAndEndsWith(TokenType t, QLatin1String str); + + inline bool recordError() { errorIndex = index; return false; } + + QVector symbols; + int index; + int errorIndex; + bool hasEscapeSequences; + QString sourcePath; +}; + +struct Q_GUI_EXPORT ValueExtractor +{ + ValueExtractor(const QVector &declarations, const QPalette & = QPalette()); + + bool extractFont(QFont *font, int *fontSizeAdjustment); + bool extractBackground(QBrush *, QString *, Repeat *, Qt::Alignment *, QCss::Origin *, QCss::Attachment *, + QCss::Origin *); + bool extractGeometry(int *w, int *h, int *minw, int *minh, int *maxw, int *maxh); + bool extractPosition(int *l, int *t, int *r, int *b, QCss::Origin *, Qt::Alignment *, + QCss::PositionMode *, Qt::Alignment *); + bool extractBox(int *margins, int *paddings, int *spacing = 0); + bool extractBorder(int *borders, QBrush *colors, BorderStyle *Styles, QSize *radii); + bool extractOutline(int *borders, QBrush *colors, BorderStyle *Styles, QSize *radii, int *offsets); + bool extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg); + int extractStyleFeatures(); + bool extractImage(QIcon *icon, Qt::Alignment *a, QSize *size); + + int lengthValue(const Declaration &decl); + +private: + void extractFont(); + void borderValue(const Declaration &decl, int *width, QCss::BorderStyle *style, QBrush *color); + LengthData lengthValue(const Value& v); + void lengthValues(const Declaration &decl, int *m); + QSize sizeValue(const Declaration &decl); + void sizeValues(const Declaration &decl, QSize *radii); + + QVector declarations; + QFont f; + int adjustment; + int fontExtracted; + QPalette pal; +}; + +} // namespace QCss + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE( QCss::BackgroundData ) +Q_DECLARE_METATYPE( QCss::LengthData ) +Q_DECLARE_METATYPE( QCss::BorderData ) + +#undef QT_CSS_DECLARE_TYPEINFO + +#endif // QT_NO_CSSPARSER + +#endif diff --git a/Telegram/private/qfont_p.h b/Telegram/private/qfont_p.h new file mode 100644 index 000000000..3979bb27a --- /dev/null +++ b/Telegram/private/qfont_p.h @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONT_P_H +#define QFONT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qfont.h" +#include "QtCore/qmap.h" +#include "QtCore/qhash.h" +#include "QtCore/qobject.h" +#include "QtCore/qstringlist.h" +#include +#include "private/qfixed_p.h" + +QT_BEGIN_NAMESPACE + +// forwards +class QFontCache; +class QFontEngine; + +struct QFontDef +{ + inline QFontDef() + : pointSize(-1.0), pixelSize(-1), + styleStrategy(QFont::PreferDefault), styleHint(QFont::AnyStyle), + weight(50), fixedPitch(false), style(QFont::StyleNormal), stretch(100), + hintingPreference(QFont::PreferDefaultHinting), ignorePitch(true), + fixedPitchComputed(0), reserved(0) + { + } + + QString family; + QString styleName; + + QStringList fallBackFamilies; + + qreal pointSize; + qreal pixelSize; + + uint styleStrategy : 16; + uint styleHint : 8; + + uint weight : 7; // 0-99 + uint fixedPitch : 1; + uint style : 2; + uint stretch : 12; // 0-4000 + + uint hintingPreference : 2; + uint ignorePitch : 1; + uint fixedPitchComputed : 1; // for Mac OS X only + int reserved : 14; // for future extensions + + bool exactMatch(const QFontDef &other) const; + bool operator==(const QFontDef &other) const + { + return pixelSize == other.pixelSize + && weight == other.weight + && style == other.style + && stretch == other.stretch + && styleHint == other.styleHint + && styleStrategy == other.styleStrategy + && ignorePitch == other.ignorePitch && fixedPitch == other.fixedPitch + && family == other.family + && styleName == other.styleName + && hintingPreference == other.hintingPreference + ; + } + inline bool operator<(const QFontDef &other) const + { + if (pixelSize != other.pixelSize) return pixelSize < other.pixelSize; + if (weight != other.weight) return weight < other.weight; + if (style != other.style) return style < other.style; + if (stretch != other.stretch) return stretch < other.stretch; + if (styleHint != other.styleHint) return styleHint < other.styleHint; + if (styleStrategy != other.styleStrategy) return styleStrategy < other.styleStrategy; + if (family != other.family) return family < other.family; + if (styleName != other.styleName) + return styleName < other.styleName; + if (hintingPreference != other.hintingPreference) return hintingPreference < other.hintingPreference; + + + if (ignorePitch != other.ignorePitch) return ignorePitch < other.ignorePitch; + if (fixedPitch != other.fixedPitch) return fixedPitch < other.fixedPitch; + return false; + } +}; + +inline uint qHash(const QFontDef &fd, uint seed = 0) Q_DECL_NOTHROW +{ + return qHash(qRound64(fd.pixelSize*10000)) // use only 4 fractional digits + ^ qHash(fd.weight) + ^ qHash(fd.style) + ^ qHash(fd.stretch) + ^ qHash(fd.styleHint) + ^ qHash(fd.styleStrategy) + ^ qHash(fd.ignorePitch) + ^ qHash(fd.fixedPitch) + ^ qHash(fd.family, seed) + ^ qHash(fd.styleName) + ^ qHash(fd.hintingPreference) + ; +} + +class QFontEngineData +{ +public: + QFontEngineData(); + ~QFontEngineData(); + + QAtomicInt ref; + const int fontCacheId; + + QFontEngine *engines[QChar::ScriptCount]; + +private: + Q_DISABLE_COPY(QFontEngineData) +}; + + +class Q_GUI_EXPORT QFontPrivate +{ +public: + + QFontPrivate(); + QFontPrivate(const QFontPrivate &other); + ~QFontPrivate(); + + QFontEngine *engineForScript(int script) const; + void alterCharForCapitalization(QChar &c) const; + + QAtomicInt ref; + QFontDef request; + mutable QFontEngineData *engineData; + int dpi; + int screen; + + uint underline : 1; + uint overline : 1; + uint strikeOut : 1; + uint kerning : 1; + uint capital : 3; + bool letterSpacingIsAbsolute : 1; + + QFixed letterSpacing; + QFixed wordSpacing; + + mutable QFontPrivate *scFont; + QFont smallCapsFont() const { return QFont(smallCapsFontPrivate()); } + QFontPrivate *smallCapsFontPrivate() const; + + static QFontPrivate *get(const QFont &font) + { + return font.d.data(); + } + + void resolve(uint mask, const QFontPrivate *other); + + static void detachButKeepEngineData(QFont *font); + +private: + QFontPrivate &operator=(const QFontPrivate &) { return *this; } +}; + + +class Q_AUTOTEST_EXPORT QFontCache : public QObject +{ +public: + // note: these static functions work on a per-thread basis + static QFontCache *instance(); + static void cleanup(); + + QFontCache(); + ~QFontCache(); + + int id() const { return m_id; } + + void clear(); + + struct Key { + Key() : script(0), multi(0), screen(0) { } + Key(const QFontDef &d, uchar c, bool m = 0, uchar s = 0) + : def(d), script(c), multi(m), screen(s) { } + + QFontDef def; + uchar script; + uchar multi: 1; + uchar screen: 7; + + inline bool operator<(const Key &other) const + { + if (script != other.script) return script < other.script; + if (screen != other.screen) return screen < other.screen; + if (multi != other.multi) return multi < other.multi; + if (multi && def.fallBackFamilies.size() != other.def.fallBackFamilies.size()) + return def.fallBackFamilies.size() < other.def.fallBackFamilies.size(); + return def < other.def; + } + inline bool operator==(const Key &other) const + { + return script == other.script + && screen == other.screen + && multi == other.multi + && (!multi || def.fallBackFamilies == other.def.fallBackFamilies) + && def == other.def; + } + }; + + // QFontEngineData cache + typedef QMap EngineDataCache; + EngineDataCache engineDataCache; + + QFontEngineData *findEngineData(const QFontDef &def) const; + void insertEngineData(const QFontDef &def, QFontEngineData *engineData); + + // QFontEngine cache + struct Engine { + Engine() : data(0), timestamp(0), hits(0) { } + Engine(QFontEngine *d) : data(d), timestamp(0), hits(0) { } + + QFontEngine *data; + uint timestamp; + uint hits; + }; + + typedef QMap EngineCache; + EngineCache engineCache; + QHash engineCacheCount; + + QFontEngine *findEngine(const Key &key); + + void updateHitCountAndTimeStamp(Engine &value); + void insertEngine(const Key &key, QFontEngine *engine, bool insertMulti = false); + +private: + void increaseCost(uint cost); + void decreaseCost(uint cost); + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; + void decreaseCache(); + + static const uint min_cost; + uint total_cost, max_cost; + uint current_timestamp; + bool fast; + int timer_id; + const int m_id; +}; + +Q_GUI_EXPORT int qt_defaultDpiX(); +Q_GUI_EXPORT int qt_defaultDpiY(); +Q_GUI_EXPORT int qt_defaultDpi(); + +QT_END_NAMESPACE + +#endif // QFONT_P_H diff --git a/Telegram/private/qfontengine_p.h b/Telegram/private/qfontengine_p.h new file mode 100644 index 000000000..1430444c7 --- /dev/null +++ b/Telegram/private/qfontengine_p.h @@ -0,0 +1,506 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTENGINE_P_H +#define QFONTENGINE_P_H + +// +// 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. +// + +#include "QtCore/qglobal.h" +#include "QtCore/qatomic.h" +#include +#include +#include +#include "private/qtextengine_p.h" +#include "private/qfont_p.h" + +QT_BEGIN_NAMESPACE + +class QPainterPath; +class QFontEngineGlyphCache; + +struct QGlyphLayout; + +#define MAKE_TAG(ch1, ch2, ch3, ch4) (\ + (((quint32)(ch1)) << 24) | \ + (((quint32)(ch2)) << 16) | \ + (((quint32)(ch3)) << 8) | \ + ((quint32)(ch4)) \ + ) + +// ### this only used in getPointInOutline(), refactor it and then remove these magic numbers +enum HB_Compat_Error { + Err_Ok = 0x0000, + Err_Not_Covered = 0xFFFF, + Err_Invalid_Argument = 0x1A66, + Err_Invalid_SubTable_Format = 0x157F, + Err_Invalid_SubTable = 0x1570 +}; + +typedef void (*qt_destroy_func_t) (void *user_data); +typedef bool (*qt_get_font_table_func_t) (void *user_data, uint tag, uchar *buffer, uint *length); + +class Q_GUI_EXPORT QFontEngine +{ +public: + enum Type { + Box, + Multi, + + // MS Windows types + Win, + + // Apple Mac OS types + Mac, + + // QWS types + Freetype, + QPF1, + QPF2, + Proxy, + + DirectWrite, + + TestFontEngine = 0x1000 + }; + + enum GlyphFormat { + Format_None, + Format_Render = Format_None, + Format_Mono, + Format_A8, + Format_A32, + Format_ARGB + }; + + enum ShaperFlag { + DesignMetrics = 0x0002, + GlyphIndicesOnly = 0x0004 + }; + Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag) + + virtual ~QFontEngine(); + + inline Type type() const { return m_type; } + + // all of these are in unscaled metrics if the engine supports uncsaled metrics, + // otherwise in design metrics + struct Properties { + QByteArray postscriptName; + QByteArray copyright; + QRectF boundingBox; + QFixed emSquare; + QFixed ascent; + QFixed descent; + QFixed leading; + QFixed italicAngle; + QFixed capHeight; + QFixed lineWidth; + }; + virtual Properties properties() const; + virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics); + QByteArray getSfntTable(uint tag) const; + virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; + + struct FaceId { + FaceId() : index(0), encoding(0) {} + QByteArray filename; + QByteArray uuid; + int index; + int encoding; + }; + virtual FaceId faceId() const { return FaceId(); } + enum SynthesizedFlags { + SynthesizedItalic = 0x1, + SynthesizedBold = 0x2, + SynthesizedStretch = 0x4 + }; + virtual int synthesized() const { return 0; } + virtual bool supportsSubPixelPositions() const { return false; } + virtual QFixed subPixelPositionForX(QFixed x) const; + + virtual QFixed emSquareSize() const { return ascent(); } + + /* returns 0 as glyph index for non existent glyphs */ + virtual glyph_t glyphIndex(uint ucs4) const = 0; + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0; + virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {} + virtual void doKerning(QGlyphLayout *, ShaperFlags) const; + + virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags); + + void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, + QVarLengthArray &glyphs_out, QVarLengthArray &positions); + + virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags); + void addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags); + /** + * Create a qimage with the alpha values for the glyph. + * Returns an image indexed_8 with index values ranging from 0=fully transparent to 255=opaque + */ + // ### Refactor this into a smaller and more flexible API. + virtual QImage alphaMapForGlyph(glyph_t); + virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition); + virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t); + virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t); + virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t); + virtual QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t); + virtual QImage *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, + GlyphFormat neededFormat, + const QTransform &t = QTransform(), + QPoint *offset = 0); + virtual void unlockAlphaMapForGlyph(); + virtual bool hasInternalCaching() const { return false; } + + virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/) + { + return boundingBox(glyph, matrix); + } + + virtual void removeGlyphFromCache(glyph_t); + + virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) = 0; + virtual glyph_metrics_t boundingBox(glyph_t glyph) = 0; + virtual glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix); + glyph_metrics_t tightBoundingBox(const QGlyphLayout &glyphs); + + virtual QFixed ascent() const = 0; + virtual QFixed descent() const = 0; + virtual QFixed leading() const = 0; + virtual QFixed xHeight() const; + virtual QFixed averageCharWidth() const; + + virtual QFixed lineThickness() const; + virtual QFixed underlinePosition() const; + + virtual qreal maxCharWidth() const = 0; + virtual qreal minLeftBearing() const; + virtual qreal minRightBearing() const; + + virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); + + inline bool canRender(uint ucs4) const { return glyphIndex(ucs4) != 0; } + virtual bool canRender(const QChar *str, int len) const; + + virtual bool supportsTransformation(const QTransform &transform) const; + + virtual int glyphCount() const; + virtual int glyphMargin(GlyphFormat format) { return format == Format_A32 ? 2 : 0; } + + virtual QFontEngine *cloneWithSize(qreal /*pixelSize*/) const { return 0; } + + virtual Qt::HANDLE handle() const; + + void *harfbuzzFont() const; + void *harfbuzzFace() const; + bool supportsScript(QChar::Script script) const; + + virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints); + + void clearGlyphCache(const void *key); + void setGlyphCache(const void *key, QFontEngineGlyphCache *data); + QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const; + + static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize); + static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode); + + static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily); + + virtual bool hasUnreliableGlyphOutline() const; + + enum HintStyle { + HintNone, + HintLight, + HintMedium, + HintFull + }; + virtual void setDefaultHintStyle(HintStyle) { } + + enum SubpixelAntialiasingType { + Subpixel_None, + Subpixel_RGB, + Subpixel_BGR, + Subpixel_VRGB, + Subpixel_VBGR + }; + +private: + const Type m_type; + +public: + QAtomicInt ref; + QFontDef fontDef; + + class Holder { // replace by std::unique_ptr once available + void *ptr; + qt_destroy_func_t destroy_func; + public: + Holder() : ptr(nullptr), destroy_func(nullptr) {} + explicit Holder(void *p, qt_destroy_func_t d) : ptr(p), destroy_func(d) {} + ~Holder() { if (ptr && destroy_func) destroy_func(ptr); } + Holder(Holder &&other) Q_DECL_NOTHROW + : ptr(other.ptr), + destroy_func(other.destroy_func) + { + other.ptr = nullptr; + other.destroy_func = nullptr; + } + Holder &operator=(Holder &&other) Q_DECL_NOTHROW + { swap(other); return *this; } + + void swap(Holder &other) Q_DECL_NOTHROW + { + qSwap(ptr, other.ptr); + qSwap(destroy_func, other.destroy_func); + } + + void *get() const Q_DECL_NOTHROW { return ptr; } + void *release() Q_DECL_NOTHROW { + void *result = ptr; + ptr = nullptr; + destroy_func = nullptr; + return result; + } + void reset() Q_DECL_NOTHROW { Holder().swap(*this); } + qt_destroy_func_t get_deleter() const Q_DECL_NOTHROW { return destroy_func; } + + bool operator!() const Q_DECL_NOTHROW { return !ptr; } + }; + + mutable Holder font_; // \ NOTE: Declared before m_glyphCaches, so font_, face_ + mutable Holder face_; // / are destroyed _after_ m_glyphCaches is destroyed. + + struct FaceData { + void *user_data; + qt_get_font_table_func_t get_font_table; + } faceData; + + uint cache_cost; // amount of mem used in bytes by the font + uint fsType : 16; + bool symbol; + struct KernPair { + uint left_right; + QFixed adjust; + + inline bool operator<(const KernPair &other) const + { + return left_right < other.left_right; + } + }; + QVector kerning_pairs; + void loadKerningPairs(QFixed scalingFactor); + + GlyphFormat glyphFormat; + QImage currentlyLockedAlphaMap; + int m_subPixelPositionCount; // Number of positions within a single pixel for this cache + + inline QVariant userData() const { return m_userData; } + +protected: + explicit QFontEngine(Type type); + + QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false); + + inline void setUserData(const QVariant &userData) { m_userData = userData; } + +private: + struct GlyphCacheEntry { + GlyphCacheEntry(); + GlyphCacheEntry(const GlyphCacheEntry &); + ~GlyphCacheEntry(); + + GlyphCacheEntry &operator=(const GlyphCacheEntry &); + + const void *context; + QExplicitlySharedDataPointer cache; + bool operator==(const GlyphCacheEntry &other) const { return context == other.context && cache == other.cache; } + }; + + mutable QLinkedList m_glyphCaches; + +private: + QVariant m_userData; + + mutable qreal m_minLeftBearing; + mutable qreal m_minRightBearing; + +}; +Q_DECLARE_TYPEINFO(QFontEngine::KernPair, Q_PRIMITIVE_TYPE); + +Q_DECLARE_OPERATORS_FOR_FLAGS(QFontEngine::ShaperFlags) + +inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2) +{ + return f1.index == f2.index && f1.encoding == f2.encoding && f1.filename == f2.filename && f1.uuid == f2.uuid; +} + +inline uint qHash(const QFontEngine::FaceId &f, uint seed = 0) + Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(f.filename))) +{ + QtPrivate::QHashCombine hash; + seed = hash(seed, f.filename); + seed = hash(seed, f.uuid); + seed = hash(seed, f.index); + seed = hash(seed, f.encoding); + return seed; +} + + +class QGlyph; + + + +class QFontEngineBox : public QFontEngine +{ +public: + QFontEngineBox(int size); + ~QFontEngineBox(); + + virtual glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const Q_DECL_OVERRIDE; + virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const Q_DECL_OVERRIDE; + + void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si); + virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; + + virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) Q_DECL_OVERRIDE; + virtual glyph_metrics_t boundingBox(glyph_t glyph) Q_DECL_OVERRIDE; + virtual QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; + + virtual QFixed ascent() const Q_DECL_OVERRIDE; + virtual QFixed descent() const Q_DECL_OVERRIDE; + virtual QFixed leading() const Q_DECL_OVERRIDE; + virtual qreal maxCharWidth() const Q_DECL_OVERRIDE; + virtual qreal minLeftBearing() const Q_DECL_OVERRIDE { return 0; } + virtual qreal minRightBearing() const Q_DECL_OVERRIDE { return 0; } + virtual QImage alphaMapForGlyph(glyph_t) Q_DECL_OVERRIDE; + + virtual bool canRender(const QChar *string, int len) const Q_DECL_OVERRIDE; + + inline int size() const { return _size; } + +protected: + explicit QFontEngineBox(Type type, int size); + +private: + friend class QFontPrivate; + int _size; +}; + +class Q_GUI_EXPORT QFontEngineMulti : public QFontEngine +{ +public: + explicit QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies = QStringList()); + ~QFontEngineMulti(); + + virtual glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const Q_DECL_OVERRIDE; + + virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) Q_DECL_OVERRIDE; + virtual glyph_metrics_t boundingBox(glyph_t glyph) Q_DECL_OVERRIDE; + + virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const Q_DECL_OVERRIDE; + virtual void doKerning(QGlyphLayout *, ShaperFlags) const Q_DECL_OVERRIDE; + virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; + virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) Q_DECL_OVERRIDE; + + virtual QFixed ascent() const Q_DECL_OVERRIDE; + virtual QFixed descent() const Q_DECL_OVERRIDE; + virtual QFixed leading() const Q_DECL_OVERRIDE; + virtual QFixed xHeight() const Q_DECL_OVERRIDE; + virtual QFixed averageCharWidth() const Q_DECL_OVERRIDE; + virtual QImage alphaMapForGlyph(glyph_t) Q_DECL_OVERRIDE; + virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) Q_DECL_OVERRIDE; + virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t) Q_DECL_OVERRIDE; + virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; + virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; + + virtual QFixed lineThickness() const Q_DECL_OVERRIDE; + virtual QFixed underlinePosition() const Q_DECL_OVERRIDE; + virtual qreal maxCharWidth() const Q_DECL_OVERRIDE; + virtual qreal minLeftBearing() const Q_DECL_OVERRIDE; + virtual qreal minRightBearing() const Q_DECL_OVERRIDE; + + virtual bool canRender(const QChar *string, int len) const Q_DECL_OVERRIDE; + + inline int fallbackFamilyCount() const { return m_fallbackFamilies.size(); } + inline QString fallbackFamilyAt(int at) const { return m_fallbackFamilies.at(at); } + + void setFallbackFamiliesList(const QStringList &fallbackFamilies); + + inline QFontEngine *engine(int at) const + { Q_ASSERT(at < m_engines.size()); return m_engines.at(at); } + + void ensureEngineAt(int at); + + static QFontEngine *createMultiFontEngine(QFontEngine *fe, int script); + +protected: + virtual void ensureFallbackFamiliesQueried(); + virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const; + virtual QFontEngine *loadEngine(int at); + +private: + QVector m_engines; + QStringList m_fallbackFamilies; + const int m_script; + bool m_fallbackFamiliesQueried; +}; + +class QTestFontEngine : public QFontEngineBox +{ +public: + QTestFontEngine(int size); +}; + +QT_END_NAMESPACE + + + +#endif // QFONTENGINE_P_H diff --git a/Telegram/private/qfragmentmap_p.h b/Telegram/private/qfragmentmap_p.h new file mode 100644 index 000000000..4cf17aadc --- /dev/null +++ b/Telegram/private/qfragmentmap_p.h @@ -0,0 +1,888 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFRAGMENTMAP_P_H +#define QFRAGMENTMAP_P_H + +// +// 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. +// + +#include "QtCore/qglobal.h" +#include +#include + +QT_BEGIN_NAMESPACE + + +template +class QFragment +{ +public: + quint32 parent; + quint32 left; + quint32 right; + quint32 color; + quint32 size_left_array[N]; + quint32 size_array[N]; + enum {size_array_max = N }; +}; + +template +class QFragmentMapData +{ + enum Color { Red, Black }; +public: + QFragmentMapData(); + ~QFragmentMapData(); + + void init(); + + class Header + { + public: + quint32 root; // this relies on being at the same position as parent in the fragment struct + quint32 tag; + quint32 freelist; + quint32 node_count; + quint32 allocated; + }; + + + enum {fragmentSize = sizeof(Fragment) }; + + + int length(uint field = 0) const; + + + inline Fragment *fragment(uint index) { + return (fragments + index); + } + inline const Fragment *fragment(uint index) const { + return (fragments + index); + } + + + inline Fragment &F(uint index) { return fragments[index] ; } + inline const Fragment &F(uint index) const { return fragments[index] ; } + + inline bool isRoot(uint index) const { + return !fragment(index)->parent; + } + + inline uint position(uint node, uint field = 0) const { + Q_ASSERT(field < Fragment::size_array_max); + const Fragment *f = fragment(node); + uint offset = f->size_left_array[field]; + while (f->parent) { + uint p = f->parent; + f = fragment(p); + if (f->right == node) + offset += f->size_left_array[field] + f->size_array[field]; + node = p; + } + return offset; + } + inline uint sizeRight(uint node, uint field = 0) const { + Q_ASSERT(field < Fragment::size_array_max); + uint sr = 0; + const Fragment *f = fragment(node); + node = f->right; + while (node) { + f = fragment(node); + sr += f->size_left_array[field] + f->size_array[field]; + node = f->right; + } + return sr; + } + inline uint sizeLeft(uint node, uint field = 0) const { + Q_ASSERT(field < Fragment::size_array_max); + return fragment(node)->size_left_array[field]; + } + + + inline uint size(uint node, uint field = 0) const { + Q_ASSERT(field < Fragment::size_array_max); + return fragment(node)->size_array[field]; + } + + inline void setSize(uint node, int new_size, uint field = 0) { + Q_ASSERT(field < Fragment::size_array_max); + Fragment *f = fragment(node); + int diff = new_size - f->size_array[field]; + f->size_array[field] = new_size; + while (f->parent) { + uint p = f->parent; + f = fragment(p); + if (f->left == node) + f->size_left_array[field] += diff; + node = p; + } + } + + + uint findNode(int k, uint field = 0) const; + + uint insert_single(int key, uint length); + uint erase_single(uint f); + + uint minimum(uint n) const { + while (n && fragment(n)->left) + n = fragment(n)->left; + return n; + } + + uint maximum(uint n) const { + while (n && fragment(n)->right) + n = fragment(n)->right; + return n; + } + + uint next(uint n) const; + uint previous(uint n) const; + + inline uint root() const { + Q_ASSERT(!head->root || !fragment(head->root)->parent); + return head->root; + } + inline void setRoot(uint new_root) { + Q_ASSERT(!head->root || !fragment(new_root)->parent); + head->root = new_root; + } + + inline bool isValid(uint n) const { + return n > 0 && n != head->freelist; + } + + union { + Header *head; + Fragment *fragments; + }; + +private: + + void rotateLeft(uint x); + void rotateRight(uint x); + void rebalance(uint x); + void removeAndRebalance(uint z); + + uint createFragment(); + void freeFragment(uint f); + +}; + +template +QFragmentMapData::QFragmentMapData() + : fragments(0) +{ + init(); +} + +template +void QFragmentMapData::init() +{ + // the following code will realloc an existing fragment or create a new one. + // it will also ignore errors when shrinking an existing fragment. + Fragment *newFragments = (Fragment *)realloc(fragments, 64*fragmentSize); + if (newFragments) { + fragments = newFragments; + head->allocated = 64; + } + Q_CHECK_PTR(fragments); + + head->tag = (((quint32)'p') << 24) | (((quint32)'m') << 16) | (((quint32)'a') << 8) | 'p'; //TAG('p', 'm', 'a', 'p'); + head->root = 0; + head->freelist = 1; + head->node_count = 0; + // mark all items to the right as unused + F(head->freelist).right = 0; +} + +template +QFragmentMapData::~QFragmentMapData() +{ + free(fragments); +} + +template +uint QFragmentMapData::createFragment() +{ + Q_ASSERT(head->freelist <= head->allocated); + + uint freePos = head->freelist; + if (freePos == head->allocated) { + // need to create some free space + if (freePos >= uint(MaxAllocSize) / fragmentSize) + qBadAlloc(); + uint needed = qAllocMore((freePos+1)*fragmentSize, 0); + Q_ASSERT(needed/fragmentSize > head->allocated); + Fragment *newFragments = (Fragment *)realloc(fragments, needed); + Q_CHECK_PTR(newFragments); + fragments = newFragments; + head->allocated = needed/fragmentSize; + F(freePos).right = 0; + } + + uint nextPos = F(freePos).right; + if (!nextPos) { + nextPos = freePos+1; + if (nextPos < head->allocated) + F(nextPos).right = 0; + } + + head->freelist = nextPos; + + ++head->node_count; + + return freePos; +} + +template +void QFragmentMapData::freeFragment(uint i) +{ + F(i).right = head->freelist; + head->freelist = i; + + --head->node_count; +} + + +template +uint QFragmentMapData::next(uint n) const { + Q_ASSERT(n); + if (F(n).right) { + n = F(n).right; + while (F(n).left) + n = F(n).left; + } else { + uint y = F(n).parent; + while (F(n).parent && n == F(y).right) { + n = y; + y = F(y).parent; + } + n = y; + } + return n; +} + +template +uint QFragmentMapData::previous(uint n) const { + if (!n) + return maximum(root()); + + if (F(n).left) { + n = F(n).left; + while (F(n).right) + n = F(n).right; + } else { + uint y = F(n).parent; + while (F(n).parent && n == F(y).left) { + n = y; + y = F(y).parent; + } + n = y; + } + return n; +} + + +/* + x y + \ / \ + y --> x b + / \ \ + a b a +*/ +template +void QFragmentMapData::rotateLeft(uint x) +{ + uint p = F(x).parent; + uint y = F(x).right; + + + if (y) { + F(x).right = F(y).left; + if (F(y).left) + F(F(y).left).parent = x; + F(y).left = x; + F(y).parent = p; + } else { + F(x).right = 0; + } + if (!p) { + Q_ASSERT(head->root == x); + head->root = y; + } + else if (x == F(p).left) + F(p).left = y; + else + F(p).right = y; + F(x).parent = y; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(y).size_left_array[field] += F(x).size_left_array[field] + F(x).size_array[field]; +} + + +/* + x y + / / \ + y --> a x + / \ / + a b b +*/ +template +void QFragmentMapData::rotateRight(uint x) +{ + uint y = F(x).left; + uint p = F(x).parent; + + if (y) { + F(x).left = F(y).right; + if (F(y).right) + F(F(y).right).parent = x; + F(y).right = x; + F(y).parent = p; + } else { + F(x).left = 0; + } + if (!p) { + Q_ASSERT(head->root == x); + head->root = y; + } + else if (x == F(p).right) + F(p).right = y; + else + F(p).left = y; + F(x).parent = y; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(x).size_left_array[field] -= F(y).size_left_array[field] + F(y).size_array[field]; +} + + +template +void QFragmentMapData::rebalance(uint x) +{ + F(x).color = Red; + + while (F(x).parent && F(F(x).parent).color == Red) { + uint p = F(x).parent; + uint pp = F(p).parent; + Q_ASSERT(pp); + if (p == F(pp).left) { + uint y = F(pp).right; + if (y && F(y).color == Red) { + F(p).color = Black; + F(y).color = Black; + F(pp).color = Red; + x = pp; + } else { + if (x == F(p).right) { + x = p; + rotateLeft(x); + p = F(x).parent; + pp = F(p).parent; + } + F(p).color = Black; + if (pp) { + F(pp).color = Red; + rotateRight(pp); + } + } + } else { + uint y = F(pp).left; + if (y && F(y).color == Red) { + F(p).color = Black; + F(y).color = Black; + F(pp).color = Red; + x = pp; + } else { + if (x == F(p).left) { + x = p; + rotateRight(x); + p = F(x).parent; + pp = F(p).parent; + } + F(p).color = Black; + if (pp) { + F(pp).color = Red; + rotateLeft(pp); + } + } + } + } + F(root()).color = Black; +} + + +template +uint QFragmentMapData::erase_single(uint z) +{ + uint w = previous(z); + uint y = z; + uint x; + uint p; + + if (!F(y).left) { + x = F(y).right; + } else if (!F(y).right) { + x = F(y).left; + } else { + y = F(y).right; + while (F(y).left) + y = F(y).left; + x = F(y).right; + } + + if (y != z) { + F(F(z).left).parent = y; + F(y).left = F(z).left; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(y).size_left_array[field] = F(z).size_left_array[field]; + if (y != F(z).right) { + /* + z y + / \ / \ + a b a b + / / + ... --> ... + / / + y x + / \ + 0 x + */ + p = F(y).parent; + if (x) + F(x).parent = p; + F(p).left = x; + F(y).right = F(z).right; + F(F(z).right).parent = y; + uint n = p; + while (n != y) { + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(n).size_left_array[field] -= F(y).size_array[field]; + n = F(n).parent; + } + } else { + /* + z y + / \ / \ + a y --> a x + / \ + 0 x + */ + p = y; + } + uint zp = F(z).parent; + if (!zp) { + Q_ASSERT(head->root == z); + head->root = y; + } else if (F(zp).left == z) { + F(zp).left = y; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(zp).size_left_array[field] -= F(z).size_array[field]; + } else { + F(zp).right = y; + } + F(y).parent = zp; + // Swap the colors + uint c = F(y).color; + F(y).color = F(z).color; + F(z).color = c; + y = z; + } else { + /* + p p p p + / / \ \ + z --> x z --> x + | | + x x + */ + p = F(z).parent; + if (x) + F(x).parent = p; + if (!p) { + Q_ASSERT(head->root == z); + head->root = x; + } else if (F(p).left == z) { + F(p).left = x; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(p).size_left_array[field] -= F(z).size_array[field]; + } else { + F(p).right = x; + } + } + uint n = z; + while (F(n).parent) { + uint p = F(n).parent; + if (F(p).left == n) { + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(p).size_left_array[field] -= F(z).size_array[field]; + } + n = p; + } + + freeFragment(z); + + + if (F(y).color != Red) { + while (F(x).parent && (x == 0 || F(x).color == Black)) { + if (x == F(p).left) { + uint w = F(p).right; + if (F(w).color == Red) { + F(w).color = Black; + F(p).color = Red; + rotateLeft(p); + w = F(p).right; + } + if ((F(w).left == 0 || F(F(w).left).color == Black) && + (F(w).right == 0 || F(F(w).right).color == Black)) { + F(w).color = Red; + x = p; + p = F(x).parent; + } else { + if (F(w).right == 0 || F(F(w).right).color == Black) { + if (F(w).left) + F(F(w).left).color = Black; + F(w).color = Red; + rotateRight(F(p).right); + w = F(p).right; + } + F(w).color = F(p).color; + F(p).color = Black; + if (F(w).right) + F(F(w).right).color = Black; + rotateLeft(p); + break; + } + } else { + uint w = F(p).left; + if (F(w).color == Red) { + F(w).color = Black; + F(p).color = Red; + rotateRight(p); + w = F(p).left; + } + if ((F(w).right == 0 || F(F(w).right).color == Black) && + (F(w).left == 0 || F(F(w).left).color == Black)) { + F(w).color = Red; + x = p; + p = F(x).parent; + } else { + if (F(w).left == 0 || F(F(w).left).color == Black) { + if (F(w).right) + F(F(w).right).color = Black; + F(w).color = Red; + rotateLeft(F(p).left); + w = F(p).left; + } + F(w).color = F(p).color; + F(p).color = Black; + if (F(w).left) + F(F(w).left).color = Black; + rotateRight(p); + break; + } + } + } + if (x) + F(x).color = Black; + } + + return w; +} + +template +uint QFragmentMapData::findNode(int k, uint field) const +{ + Q_ASSERT(field < Fragment::size_array_max); + uint x = root(); + + uint s = k; + while (x) { + if (sizeLeft(x, field) <= s) { + if (s < sizeLeft(x, field) + size(x, field)) + return x; + s -= sizeLeft(x, field) + size(x, field); + x = F(x).right; + } else { + x = F(x).left; + } + } + return 0; +} + +template +uint QFragmentMapData::insert_single(int key, uint length) +{ + Q_ASSERT(!findNode(key) || (int)this->position(findNode(key)) == key); + + uint z = createFragment(); + + F(z).left = 0; + F(z).right = 0; + F(z).size_array[0] = length; + for (uint field = 1; field < Fragment::size_array_max; ++field) + F(z).size_array[field] = 1; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(z).size_left_array[field] = 0; + + uint y = 0; + uint x = root(); + + Q_ASSERT(!x || F(x).parent == 0); + + uint s = key; + bool right = false; + while (x) { + y = x; + if (s <= F(x).size_left_array[0]) { + x = F(x).left; + right = false; + } else { + s -= F(x).size_left_array[0] + F(x).size_array[0]; + x = F(x).right; + right = true; + } + } + + F(z).parent = y; + if (!y) { + head->root = z; + } else if (!right) { + F(y).left = z; + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(y).size_left_array[field] = F(z).size_array[field]; + } else { + F(y).right = z; + } + while (y && F(y).parent) { + uint p = F(y).parent; + if (F(p).left == y) { + for (uint field = 0; field < Fragment::size_array_max; ++field) + F(p).size_left_array[field] += F(z).size_array[field]; + } + y = p; + } + rebalance(z); + + return z; +} + + +template +int QFragmentMapData::length(uint field) const { + uint root = this->root(); + return root ? sizeLeft(root, field) + size(root, field) + sizeRight(root, field) : 0; +} + + +template // NOTE: must inherit QFragment +class QFragmentMap +{ +public: + class Iterator + { + public: + QFragmentMap *pt; + quint32 n; + + Iterator() : pt(0), n(0) {} + Iterator(QFragmentMap *p, int node) : pt(p), n(node) {} + Iterator(const Iterator& it) : pt(it.pt), n(it.n) {} + + inline bool atEnd() const { return !n; } + + bool operator==(const Iterator& it) const { return pt == it.pt && n == it.n; } + bool operator!=(const Iterator& it) const { return pt != it.pt || n != it.n; } + bool operator<(const Iterator &it) const { return position() < it.position(); } + + Fragment *operator*() { Q_ASSERT(!atEnd()); return pt->fragment(n); } + const Fragment *operator*() const { Q_ASSERT(!atEnd()); return pt->fragment(n); } + Fragment *operator->() { Q_ASSERT(!atEnd()); return pt->fragment(n); } + const Fragment *operator->() const { Q_ASSERT(!atEnd()); return pt->fragment(n); } + + int position() const { Q_ASSERT(!atEnd()); return pt->data.position(n); } + const Fragment *value() const { Q_ASSERT(!atEnd()); return pt->fragment(n); } + Fragment *value() { Q_ASSERT(!atEnd()); return pt->fragment(n); } + + Iterator& operator++() { + n = pt->data.next(n); + return *this; + } + Iterator& operator--() { + n = pt->data.previous(n); + return *this; + } + + }; + + + class ConstIterator + { + public: + const QFragmentMap *pt; + quint32 n; + + /** + * Functions + */ + ConstIterator() : pt(0), n(0) {} + ConstIterator(const QFragmentMap *p, int node) : pt(p), n(node) {} + ConstIterator(const ConstIterator& it) : pt(it.pt), n(it.n) {} + ConstIterator(const Iterator& it) : pt(it.pt), n(it.n) {} + + inline bool atEnd() const { return !n; } + + bool operator==(const ConstIterator& it) const { return pt == it.pt && n == it.n; } + bool operator!=(const ConstIterator& it) const { return pt != it.pt || n != it.n; } + bool operator<(const ConstIterator &it) const { return position() < it.position(); } + + const Fragment *operator*() const { Q_ASSERT(!atEnd()); return pt->fragment(n); } + const Fragment *operator->() const { Q_ASSERT(!atEnd()); return pt->fragment(n); } + + int position() const { Q_ASSERT(!atEnd()); return pt->data.position(n); } + int size() const { Q_ASSERT(!atEnd()); return pt->data.size(n); } + const Fragment *value() const { Q_ASSERT(!atEnd()); return pt->fragment(n); } + + ConstIterator& operator++() { + n = pt->data.next(n); + return *this; + } + ConstIterator& operator--() { + n = pt->data.previous(n); + return *this; + } + }; + + + QFragmentMap() {} + ~QFragmentMap() + { + if (!data.fragments) + return; // in case of out-of-memory, we won't have fragments + for (Iterator it = begin(); !it.atEnd(); ++it) + it.value()->free(); + } + + inline void clear() { + for (Iterator it = begin(); !it.atEnd(); ++it) + it.value()->free(); + data.init(); + } + + inline Iterator begin() { return Iterator(this, data.minimum(data.root())); } + inline Iterator end() { return Iterator(this, 0); } + inline ConstIterator begin() const { return ConstIterator(this, data.minimum(data.root())); } + inline ConstIterator end() const { return ConstIterator(this, 0); } + + inline ConstIterator last() const { return ConstIterator(this, data.maximum(data.root())); } + + inline bool isEmpty() const { return data.head->node_count == 0; } + inline int numNodes() const { return data.head->node_count; } + int length(uint field = 0) const { return data.length(field); } + + Iterator find(int k, uint field = 0) { return Iterator(this, data.findNode(k, field)); } + ConstIterator find(int k, uint field = 0) const { return ConstIterator(this, data.findNode(k, field)); } + + uint findNode(int k, uint field = 0) const { return data.findNode(k, field); } + + uint insert_single(int key, uint length) + { + uint f = data.insert_single(key, length); + if (f != 0) { + Fragment *frag = fragment(f); + Q_ASSERT(frag); + frag->initialize(); + } + return f; + } + uint erase_single(uint f) + { + if (f != 0) { + Fragment *frag = fragment(f); + Q_ASSERT(frag); + frag->free(); + } + return data.erase_single(f); + } + + inline Fragment *fragment(uint index) { + Q_ASSERT(index != 0); + return data.fragment(index); + } + inline const Fragment *fragment(uint index) const { + Q_ASSERT(index != 0); + return data.fragment(index); + } + inline uint position(uint node, uint field = 0) const { return data.position(node, field); } + inline bool isValid(uint n) const { return data.isValid(n); } + inline uint next(uint n) const { return data.next(n); } + inline uint previous(uint n) const { return data.previous(n); } + inline uint size(uint node, uint field = 0) const { return data.size(node, field); } + inline void setSize(uint node, int new_size, uint field = 0) + { data.setSize(node, new_size, field); + if (node != 0 && field == 0) { + Fragment *frag = fragment(node); + Q_ASSERT(frag); + frag->invalidate(); + } + } + + inline int firstNode() const { return data.minimum(data.root()); } + +private: + friend class Iterator; + friend class ConstIterator; + + QFragmentMapData data; + + QFragmentMap(const QFragmentMap& m); + QFragmentMap& operator= (const QFragmentMap& m); +}; + +QT_END_NAMESPACE + +#endif // QFRAGMENTMAP_P_H diff --git a/Telegram/private/qharfbuzz_p.h b/Telegram/private/qharfbuzz_p.h new file mode 100644 index 000000000..cc4d9bbd8 --- /dev/null +++ b/Telegram/private/qharfbuzz_p.h @@ -0,0 +1,355 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// 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. +// + +#ifndef QHARFBUZZ_P_H +#define QHARFBUZZ_P_H + +#include + +#if defined(QT_BUILD_CORE_LIB) +# include +#else +// a minimal set of HB types required for Qt libs other than Core +extern "C" { + +typedef enum { + /* no error */ + HB_Err_Ok = 0x0000, + HB_Err_Not_Covered = 0xFFFF, + + /* _hb_err() is called whenever returning the following errors, + * and in a couple places for HB_Err_Not_Covered too. */ + + /* programmer error */ + HB_Err_Invalid_Argument = 0x1A66, + + /* font error */ + HB_Err_Invalid_SubTable_Format = 0x157F, + HB_Err_Invalid_SubTable = 0x1570, + HB_Err_Read_Error = 0x6EAD, + + /* system error */ + HB_Err_Out_Of_Memory = 0xDEAD +} HB_Error; + +typedef QT_PREPEND_NAMESPACE(qint8) hb_int8; +typedef QT_PREPEND_NAMESPACE(quint8) hb_uint8; +typedef QT_PREPEND_NAMESPACE(qint16) hb_int16; +typedef QT_PREPEND_NAMESPACE(quint16) hb_uint16; +typedef QT_PREPEND_NAMESPACE(qint32) hb_int32; +typedef QT_PREPEND_NAMESPACE(quint32) hb_uint32; + +typedef hb_uint8 HB_Bool; +typedef hb_uint8 HB_Byte; +typedef hb_uint16 HB_UShort; +typedef hb_uint32 HB_UInt; +typedef hb_int8 HB_Char; +typedef hb_int16 HB_Short; +typedef hb_int32 HB_Int; +typedef hb_uint16 HB_UChar16; +typedef hb_uint32 HB_UChar32; +typedef hb_uint32 HB_Glyph; +typedef hb_int32 HB_Fixed; /* 26.6 */ +typedef hb_int32 HB_16Dot16; /* 16.16 */ +typedef hb_uint32 HB_Tag; + +typedef struct { + HB_Fixed x; + HB_Fixed y; +} HB_FixedPoint; + +typedef enum { + HB_Script_Common, + HB_Script_Greek, + HB_Script_Cyrillic, + HB_Script_Armenian, + HB_Script_Hebrew, + HB_Script_Arabic, + HB_Script_Syriac, + HB_Script_Thaana, + HB_Script_Devanagari, + HB_Script_Bengali, + HB_Script_Gurmukhi, + HB_Script_Gujarati, + HB_Script_Oriya, + HB_Script_Tamil, + HB_Script_Telugu, + HB_Script_Kannada, + HB_Script_Malayalam, + HB_Script_Sinhala, + HB_Script_Thai, + HB_Script_Lao, + HB_Script_Tibetan, + HB_Script_Myanmar, + HB_Script_Georgian, + HB_Script_Hangul, + HB_Script_Ogham, + HB_Script_Runic, + HB_Script_Khmer, + HB_Script_Nko, + HB_Script_Inherited, + HB_ScriptCount = HB_Script_Inherited +} HB_Script; + +#ifdef __xlC__ +typedef unsigned hb_bitfield; +#else +typedef hb_uint8 hb_bitfield; +#endif + +typedef struct { + hb_bitfield justification :4; /* Justification class */ + hb_bitfield clusterStart :1; /* First glyph of representation of cluster */ + hb_bitfield mark :1; /* needs to be positioned around base char */ + hb_bitfield zeroWidth :1; /* ZWJ, ZWNJ etc, with no width */ + hb_bitfield dontPrint :1; + hb_bitfield combiningClass :8; +} HB_GlyphAttributes; + +typedef void * HB_GDEF; +typedef void * HB_GSUB; +typedef void * HB_GPOS; +typedef void * HB_Buffer; + +typedef HB_Error (*HB_GetFontTableFunc)(void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length); + +typedef struct HB_FaceRec_ { + HB_Bool isSymbolFont; + + HB_GDEF gdef; + HB_GSUB gsub; + HB_GPOS gpos; + HB_Bool supported_scripts[HB_ScriptCount]; + HB_Buffer buffer; + HB_Script current_script; + int current_flags; /* HB_ShaperFlags */ + HB_Bool has_opentype_kerning; + HB_Bool glyphs_substituted; + HB_GlyphAttributes *tmpAttributes; + unsigned int *tmpLogClusters; + int length; + int orig_nglyphs; + void *font_for_init; + HB_GetFontTableFunc get_font_table_func; +} HB_FaceRec; + +typedef struct { + HB_Fixed x, y; + HB_Fixed width, height; + HB_Fixed xOffset, yOffset; +} HB_GlyphMetrics; + +typedef enum { + HB_FontAscent +} HB_FontMetric; + +struct HB_Font_; +typedef struct HB_Font_ *HB_Font; +typedef struct HB_FaceRec_ *HB_Face; + +typedef struct { + HB_Bool (*convertStringToGlyphIndices)(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft); + void (*getGlyphAdvances)(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, int flags /*HB_ShaperFlag*/); + HB_Bool (*canRender)(HB_Font font, const HB_UChar16 *string, hb_uint32 length); + /* implementation needs to make sure to load a scaled glyph, so /no/ FT_LOAD_NO_SCALE */ + HB_Error (*getPointInOutline)(HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); + void (*getGlyphMetrics)(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics); + HB_Fixed (*getFontMetric)(HB_Font font, HB_FontMetric metric); +} HB_FontClass; + +typedef struct HB_Font_ { + const HB_FontClass *klass; + + /* Metrics */ + HB_UShort x_ppem, y_ppem; + HB_16Dot16 x_scale, y_scale; + + void *userData; +} HB_FontRec; + +typedef enum { + HB_LeftToRight = 0, + HB_RightToLeft = 1 +} HB_StringToGlyphsFlags; + +typedef enum { + HB_ShaperFlag_Default = 0, + HB_ShaperFlag_NoKerning = 1, + HB_ShaperFlag_UseDesignMetrics = 2 +} HB_ShaperFlag; + +typedef struct +{ + hb_uint32 pos; + hb_uint32 length; + HB_Script script; + hb_uint8 bidiLevel; +} HB_ScriptItem; + +typedef struct HB_ShaperItem_ HB_ShaperItem; + +struct HB_ShaperItem_ { + const HB_UChar16 *string; /* input: the Unicode UTF16 text to be shaped */ + hb_uint32 stringLength; /* input: the length of the input in 16-bit words */ + HB_ScriptItem item; /* input: the current run to be shaped: a run of text all in the same script that is a substring of */ + HB_Font font; /* input: the font: scale, units and function pointers supplying glyph indices and metrics */ + HB_Face face; /* input: the shaper state; current script, access to the OpenType tables , etc. */ + int shaperFlags; /* input (unused) should be set to 0; intended to support flags defined in HB_ShaperFlag */ + HB_Bool glyphIndicesPresent; /* input: true if the array contains glyph indices ready to be shaped */ + hb_uint32 initialGlyphCount; /* input: if glyphIndicesPresent is true, the number of glyph indices in the array */ + + hb_uint32 num_glyphs; /* input: capacity of output arrays , , , , and ; */ + /* output: required capacity (may be larger than actual capacity) */ + + HB_Glyph *glyphs; /* output: indices of shaped glyphs */ + HB_GlyphAttributes *attributes; /* output: glyph attributes */ + HB_Fixed *advances; /* output: advances */ + HB_FixedPoint *offsets; /* output: offsets */ + unsigned short *log_clusters; /* output: for each output glyph, the index in the input of the start of its logical cluster */ + + /* internal */ + HB_Bool kerning_applied; /* output: true if kerning was applied by the shaper */ +}; + +} + +#endif // QT_BUILD_CORE_LIB + + +QT_BEGIN_NAMESPACE + +static inline HB_Script script_to_hbscript(uchar script) +{ + switch (script) { + case QChar::Script_Inherited: return HB_Script_Inherited; + case QChar::Script_Common: return HB_Script_Common; + case QChar::Script_Arabic: return HB_Script_Arabic; + case QChar::Script_Armenian: return HB_Script_Armenian; + case QChar::Script_Bengali: return HB_Script_Bengali; + case QChar::Script_Cyrillic: return HB_Script_Cyrillic; + case QChar::Script_Devanagari: return HB_Script_Devanagari; + case QChar::Script_Georgian: return HB_Script_Georgian; + case QChar::Script_Greek: return HB_Script_Greek; + case QChar::Script_Gujarati: return HB_Script_Gujarati; + case QChar::Script_Gurmukhi: return HB_Script_Gurmukhi; + case QChar::Script_Hangul: return HB_Script_Hangul; + case QChar::Script_Hebrew: return HB_Script_Hebrew; + case QChar::Script_Kannada: return HB_Script_Kannada; + case QChar::Script_Khmer: return HB_Script_Khmer; + case QChar::Script_Lao: return HB_Script_Lao; + case QChar::Script_Malayalam: return HB_Script_Malayalam; + case QChar::Script_Myanmar: return HB_Script_Myanmar; + case QChar::Script_Ogham: return HB_Script_Ogham; + case QChar::Script_Oriya: return HB_Script_Oriya; + case QChar::Script_Runic: return HB_Script_Runic; + case QChar::Script_Sinhala: return HB_Script_Sinhala; + case QChar::Script_Syriac: return HB_Script_Syriac; + case QChar::Script_Tamil: return HB_Script_Tamil; + case QChar::Script_Telugu: return HB_Script_Telugu; + case QChar::Script_Thaana: return HB_Script_Thaana; + case QChar::Script_Thai: return HB_Script_Thai; + case QChar::Script_Tibetan: return HB_Script_Tibetan; + case QChar::Script_Nko: return HB_Script_Nko; + default: break; + }; + return HB_Script_Common; +} + +static inline uchar hbscript_to_script(uchar script) +{ + switch (script) { + case HB_Script_Inherited: return QChar::Script_Inherited; + case HB_Script_Common: return QChar::Script_Common; + case HB_Script_Arabic: return QChar::Script_Arabic; + case HB_Script_Armenian: return QChar::Script_Armenian; + case HB_Script_Bengali: return QChar::Script_Bengali; + case HB_Script_Cyrillic: return QChar::Script_Cyrillic; + case HB_Script_Devanagari: return QChar::Script_Devanagari; + case HB_Script_Georgian: return QChar::Script_Georgian; + case HB_Script_Greek: return QChar::Script_Greek; + case HB_Script_Gujarati: return QChar::Script_Gujarati; + case HB_Script_Gurmukhi: return QChar::Script_Gurmukhi; + case HB_Script_Hangul: return QChar::Script_Hangul; + case HB_Script_Hebrew: return QChar::Script_Hebrew; + case HB_Script_Kannada: return QChar::Script_Kannada; + case HB_Script_Khmer: return QChar::Script_Khmer; + case HB_Script_Lao: return QChar::Script_Lao; + case HB_Script_Malayalam: return QChar::Script_Malayalam; + case HB_Script_Myanmar: return QChar::Script_Myanmar; + case HB_Script_Ogham: return QChar::Script_Ogham; + case HB_Script_Oriya: return QChar::Script_Oriya; + case HB_Script_Runic: return QChar::Script_Runic; + case HB_Script_Sinhala: return QChar::Script_Sinhala; + case HB_Script_Syriac: return QChar::Script_Syriac; + case HB_Script_Tamil: return QChar::Script_Tamil; + case HB_Script_Telugu: return QChar::Script_Telugu; + case HB_Script_Thaana: return QChar::Script_Thaana; + case HB_Script_Thai: return QChar::Script_Thai; + case HB_Script_Tibetan: return QChar::Script_Tibetan; + case HB_Script_Nko: return QChar::Script_Nko; + default: break; + }; + return QChar::Script_Common; +} + +Q_CORE_EXPORT HB_Bool qShapeItem(HB_ShaperItem *item); + +// ### temporary +Q_CORE_EXPORT HB_Face qHBNewFace(void *font, HB_GetFontTableFunc tableFunc); +Q_CORE_EXPORT void qHBFreeFace(HB_Face); +Q_CORE_EXPORT HB_Face qHBLoadFace(HB_Face face); + +Q_DECLARE_TYPEINFO(HB_GlyphAttributes, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(HB_FixedPoint, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(HB_ScriptItem, Q_PRIMITIVE_TYPE); + +QT_END_NAMESPACE + +#endif // QHARFBUZZ_P_H diff --git a/Telegram/private/qobject_p.h b/Telegram/private/qobject_p.h new file mode 100644 index 000000000..4383ece24 --- /dev/null +++ b/Telegram/private/qobject_p.h @@ -0,0 +1,441 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2013 Olivier Goffart +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOBJECT_P_H +#define QOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qpointer.h" +#include "QtCore/qsharedpointer.h" +#include "QtCore/qcoreevent.h" +#include "QtCore/qlist.h" +#include "QtCore/qvector.h" +#include "QtCore/qvariant.h" +#include "QtCore/qreadwritelock.h" + +QT_BEGIN_NAMESPACE + +class QVariant; +class QThreadData; +class QObjectConnectionListVector; +namespace QtSharedPointer { struct ExternalRefCountData; } + +/* for Qt Test */ +struct QSignalSpyCallbackSet +{ + typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv); + typedef void (*EndCallback)(QObject *caller, int signal_or_method_index); + BeginCallback signal_begin_callback, + slot_begin_callback; + EndCallback signal_end_callback, + slot_end_callback; +}; +void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set); + +extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set; + +enum { QObjectPrivateVersion = QT_VERSION }; + +class Q_CORE_EXPORT QAbstractDeclarativeData +{ +public: + static void (*destroyed)(QAbstractDeclarativeData *, QObject *); + static void (*destroyed_qml1)(QAbstractDeclarativeData *, QObject *); + static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *); + static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **); + static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int); + static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int); + static void (*setWidgetParent)(QObject *, QObject *); // Used by the QML engine to specify parents for widgets. Set by QtWidgets. +}; + +// This is an implementation of QAbstractDeclarativeData that is identical with +// the implementation in QtDeclarative and QtQml for the first bit +struct QAbstractDeclarativeDataImpl : public QAbstractDeclarativeData +{ + quint32 ownedByQml1:1; + quint32 unused: 31; +}; + +class Q_CORE_EXPORT QObjectPrivate : public QObjectData +{ + Q_DECLARE_PUBLIC(QObject) + +public: + struct ExtraData + { + ExtraData() {} + #ifndef QT_NO_USERDATA + QVector userData; + #endif + QList propertyNames; + QVector propertyValues; + QVector runningTimers; + QList > eventFilters; + QString objectName; + }; + + typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **); + struct Connection + { + QObject *sender; + QObject *receiver; + union { + StaticMetaCallFunction callFunction; + QtPrivate::QSlotObjectBase *slotObj; + }; + // The next pointer for the singly-linked ConnectionList + Connection *nextConnectionList; + //senders linked list + Connection *next; + Connection **prev; + QAtomicPointer argumentTypes; + QAtomicInt ref_; + ushort method_offset; + ushort method_relative; + uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex()) + ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking + ushort isSlotObject : 1; + ushort ownArgumentTypes : 1; + Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) { + //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection + } + ~Connection(); + int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; } + void ref() { ref_.ref(); } + void deref() { + if (!ref_.deref()) { + Q_ASSERT(!receiver); + delete this; + } + } + }; + // ConnectionList is a singly-linked list + struct ConnectionList { + ConnectionList() : first(0), last(0) {} + Connection *first; + Connection *last; + }; + + struct Sender + { + QObject *sender; + int signal; + int ref; + }; + + + QObjectPrivate(int version = QObjectPrivateVersion); + virtual ~QObjectPrivate(); + void deleteChildren(); + + void setParent_helper(QObject *); + void moveToThread_helper(); + void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); + void _q_reregisterTimers(void *pointer); + + bool isSender(const QObject *receiver, const char *signal) const; + QObjectList receiverList(const char *signal) const; + QObjectList senderList() const; + + void addConnection(int signal, Connection *c); + void cleanConnectionLists(); + + static inline Sender *setCurrentSender(QObject *receiver, + Sender *sender); + static inline void resetCurrentSender(QObject *receiver, + Sender *currentSender, + Sender *previousSender); + + static QObjectPrivate *get(QObject *o) { + return o->d_func(); + } + + int signalIndex(const char *signalName, const QMetaObject **meta = 0) const; + inline bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const; + inline bool isDeclarativeSignalConnected(uint signalIdx) const; + + // To allow abitrary objects to call connectNotify()/disconnectNotify() without making + // the API public in QObject. This is used by QQmlNotifierEndpoint. + inline void connectNotify(const QMetaMethod &signal); + inline void disconnectNotify(const QMetaMethod &signal); + + template + static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, + const typename QtPrivate::FunctionPointer::Object *receiverPrivate, Func2 slot, + Qt::ConnectionType type = Qt::AutoConnection); + + template + static inline bool disconnect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, + const typename QtPrivate::FunctionPointer::Object *receiverPrivate, Func2 slot); + + static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, + const QObject *receiver, void **slot, + QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, + const int *types, const QMetaObject *senderMetaObject); + static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); + static bool disconnect(const QObject *sender, int signal_index, void **slot); +public: + ExtraData *extraData; // extra data set by the user + QThreadData *threadData; // id of the thread that owns the object + + QObjectConnectionListVector *connectionLists; + + Connection *senders; // linked list of connections connected to this object + Sender *currentSender; // object currently activating the object + mutable quint32 connectedSignals[2]; + + union { + QObject *currentChildBeingDeleted; + QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module + }; + + // these objects are all used to indicate that a QObject was deleted + // plus QPointer, which keeps a separate list + QAtomicPointer sharedRefcount; +}; + + +/*! \internal + + Returns \c true if the signal with index \a signal_index from object \a sender is connected. + Signals with indices above a certain range are always considered connected (see connectedSignals + in QObjectPrivate). + + \a signal_index must be the index returned by QObjectPrivate::signalIndex; +*/ +inline bool QObjectPrivate::isSignalConnected(uint signal_index, bool checkDeclarative) const +{ + return signal_index >= sizeof(connectedSignals) * 8 + || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f)) + || (checkDeclarative && isDeclarativeSignalConnected(signal_index))); +} + +inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const +{ + return declarativeData && QAbstractDeclarativeData::isSignalConnected + && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index); +} + +inline QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, + Sender *sender) +{ + Sender *previousSender = receiver->d_func()->currentSender; + receiver->d_func()->currentSender = sender; + return previousSender; +} + +inline void QObjectPrivate::resetCurrentSender(QObject *receiver, + Sender *currentSender, + Sender *previousSender) +{ + // ref is set to zero when this object is deleted during the metacall + if (currentSender->ref == 1) + receiver->d_func()->currentSender = previousSender; + // if we've recursed, we need to tell the caller about the objects deletion + if (previousSender) + previousSender->ref = currentSender->ref; +} + +inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) +{ + q_ptr->connectNotify(signal); +} + +inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) +{ + q_ptr->disconnectNotify(signal); +} + +namespace QtPrivate { +template class QPrivateSlotObject : public QSlotObjectBase +{ + typedef QtPrivate::FunctionPointer FuncType; + Func function; + static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) + { + switch (which) { + case Destroy: + delete static_cast(this_); + break; + case Call: + FuncType::template call(static_cast(this_)->function, + static_cast(QObjectPrivate::get(r)), a); + break; + case Compare: + *ret = *reinterpret_cast(a) == static_cast(this_)->function; + break; + case NumOperations: ; + } + } +public: + explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} +}; +} //namespace QtPrivate + +template +inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, + const typename QtPrivate::FunctionPointer::Object *receiverPrivate, Func2 slot, + Qt::ConnectionType type) +{ + typedef QtPrivate::FunctionPointer SignalType; + typedef QtPrivate::FunctionPointer SlotType; + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); + + //compilation error if the arguments does not match. + Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), + "The slot requires more arguments than the signal provides."); + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), + "Signal and slot arguments are not compatible."); + Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), + "Return type of the slot is not compatible with the return type of the signal."); + + const int *types = 0; + if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) + types = QtPrivate::ConnectionTypes::types(); + + return QObject::connectImpl(sender, reinterpret_cast(&signal), + receiverPrivate->q_ptr, reinterpret_cast(&slot), + new QtPrivate::QPrivateSlotObject::Value, + typename SignalType::ReturnType>(slot), + type, types, &SignalType::Object::staticMetaObject); +} + +template +bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal, + const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot) +{ + typedef QtPrivate::FunctionPointer SignalType; + typedef QtPrivate::FunctionPointer SlotType; + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); + //compilation error if the arguments does not match. + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), + "Signal and slot arguments are not compatible."); + return QObject::disconnectImpl(sender, reinterpret_cast(&signal), + receiverPrivate->q_ptr, reinterpret_cast(&slot), + &SignalType::Object::staticMetaObject); +} + +Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE); + +class QSemaphore; +class Q_CORE_EXPORT QMetaCallEvent : public QEvent +{ +public: + QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId, + int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); + /*! \internal + \a signalId is in the signal index range (see QObjectPrivate::signalIndex()). + */ + QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId, + int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); + + ~QMetaCallEvent(); + + inline int id() const { return method_offset_ + method_relative_; } + inline const QObject *sender() const { return sender_; } + inline int signalId() const { return signalId_; } + inline void **args() const { return args_; } + + virtual void placeMetaCall(QObject *object); + +private: + QtPrivate::QSlotObjectBase *slotObj_; + const QObject *sender_; + int signalId_; + int nargs_; + int *types_; + void **args_; + QSemaphore *semaphore_; + QObjectPrivate::StaticMetaCallFunction callFunction_; + ushort method_offset_; + ushort method_relative_; +}; + +class QBoolBlocker +{ + Q_DISABLE_COPY(QBoolBlocker) +public: + explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} + inline ~QBoolBlocker(){block = reset; } +private: + bool █ + bool reset; +}; + +void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); + +struct QAbstractDynamicMetaObject; +struct Q_CORE_EXPORT QDynamicMetaObjectData +{ + virtual ~QDynamicMetaObjectData(); + virtual void objectDestroyed(QObject *) { delete this; } + + virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0; + virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0; +}; + +struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject +{ + ~QAbstractDynamicMetaObject(); + + virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) Q_DECL_OVERRIDE { return this; } + virtual int createProperty(const char *, const char *) { return -1; } + virtual int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) Q_DECL_OVERRIDE + { return metaCall(c, _id, a); } + virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload +}; + +QT_END_NAMESPACE + +#endif // QOBJECT_P_H diff --git a/Telegram/private/qtextdocument_p.h b/Telegram/private/qtextdocument_p.h new file mode 100644 index 000000000..85a6319ea --- /dev/null +++ b/Telegram/private/qtextdocument_p.h @@ -0,0 +1,411 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTDOCUMENT_P_H +#define QTEXTDOCUMENT_P_H + +// +// 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. +// + +#include "QtCore/qglobal.h" +#include "QtCore/qstring.h" +#include "QtCore/qvector.h" +#include "QtCore/qlist.h" +#include "private/qobject_p.h" +#include "private/qfragmentmap_p.h" +#include "private/qtextlayout.h" +#include "QtGui/qtextoption.h" +#include "private/qtextformat_p.h" +#include "QtGui/qtextdocument.h" +#include "QtGui/qtextobject.h" +#include "QtGui/qtextcursor.h" +#include "QtCore/qmap.h" +#include "QtCore/qvariant.h" +#include "QtCore/qurl.h" +#include "private/qcssparser_p.h" + +// #define QT_QMAP_DEBUG + +#ifdef QT_QMAP_DEBUG +#include +#endif + +QT_BEGIN_NAMESPACE + +class QTextFormatCollection; +class QTextFormat; +class QTextBlockFormat; +class QTextCursorPrivate; +class QAbstractTextDocumentLayout; +class QTextDocument; +class QTextFrame; + +#define QTextBeginningOfFrame QChar(0xfdd0) +#define QTextEndOfFrame QChar(0xfdd1) + +class QTextFragmentData : public QFragment<> +{ +public: + inline void initialize() {} + inline void invalidate() const {} + inline void free() {} + int stringPosition; + int format; +}; + +class QTextBlockData : public QFragment<3> +{ +public: + inline void initialize() + { layout = 0; userData = 0; userState = -1; revision = 0; hidden = 0; } + void invalidate() const; + inline void free() + { delete layout; layout = 0; delete userData; userData = 0; } + + mutable int format; + // ##### probably store a QTextEngine * here! + mutable QTextLayout *layout; + mutable QTextBlockUserData *userData; + mutable int userState; + mutable int revision : 31; + mutable uint hidden : 1; +}; + + +class QAbstractUndoItem; + +class QTextUndoCommand +{ +public: + enum Command { + Inserted = 0, + Removed = 1, + CharFormatChanged = 2, + BlockFormatChanged = 3, + BlockInserted = 4, + BlockRemoved = 5, + BlockAdded = 6, + BlockDeleted = 7, + GroupFormatChange = 8, + CursorMoved = 9, + Custom = 256 + }; + enum Operation { + KeepCursor = 0, + MoveCursor = 1 + }; + quint16 command; + uint block_part : 1; // all commands that are part of an undo block (including the first and the last one) have this set to 1 + uint block_end : 1; // the last command in an undo block has this set to 1. + uint block_padding : 6; // padding since block used to be a quint8 + quint8 operation; + int format; + quint32 strPos; + quint32 pos; + union { + int blockFormat; + quint32 length; + QAbstractUndoItem *custom; + int objectIndex; + }; + quint32 revision; + + bool tryMerge(const QTextUndoCommand &other); +}; +Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE); + +class Q_AUTOTEST_EXPORT QTextDocumentPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QTextDocument) +public: + typedef QFragmentMap FragmentMap; + typedef FragmentMap::ConstIterator FragmentIterator; + typedef QFragmentMap BlockMap; + + QTextDocumentPrivate(); + ~QTextDocumentPrivate(); + + void init(); + void clear(); + + void setLayout(QAbstractTextDocumentLayout *layout); + + void insert(int pos, const QString &text, int format); + void insert(int pos, int strPos, int strLength, int format); + int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor); + int insertBlock(QChar blockSeparator, int pos, int blockFormat, int charFormat, + QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor); + + void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor); + void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor); + + void aboutToRemoveCell(int cursorFrom, int cursorEnd); + + QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format); + void removeFrame(QTextFrame *frame); + + enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices }; + + void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat); + void setBlockFormat(const QTextBlock &from, const QTextBlock &to, + const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat); + + void emitUndoAvailable(bool available); + void emitRedoAvailable(bool available); + + int undoRedo(bool undo); + inline void undo() { undoRedo(true); } + inline void redo() { undoRedo(false); } + void appendUndoItem(QAbstractUndoItem *); + inline void beginEditBlock() { if (0 == editBlock++) ++revision; } + void joinPreviousEditBlock(); + void endEditBlock(); + void finishEdit(); + inline bool isInEditBlock() const { return editBlock; } + void enableUndoRedo(bool enable); + inline bool isUndoRedoEnabled() const { return undoEnabled; } + + inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; } + inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); } + + inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; } + inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; } + + inline QString buffer() const { return text; } + QString plainText() const; + inline int length() const { return fragments.length(); } + + inline QTextFormatCollection *formatCollection() { return &formats; } + inline const QTextFormatCollection *formatCollection() const { return &formats; } + inline QAbstractTextDocumentLayout *layout() const { return lout; } + + inline FragmentIterator find(int pos) const { return fragments.find(pos); } + inline FragmentIterator begin() const { return fragments.begin(); } + inline FragmentIterator end() const { return fragments.end(); } + + inline QTextBlock blocksBegin() const { return QTextBlock(const_cast(this), blocks.firstNode()); } + inline QTextBlock blocksEnd() const { return QTextBlock(const_cast(this), 0); } + inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast(this), blocks.findNode(pos)); } + int blockCharFormatIndex(int node) const; + + inline int numBlocks() const { return blocks.numNodes(); } + + const BlockMap &blockMap() const { return blocks; } + const FragmentMap &fragmentMap() const { return fragments; } + BlockMap &blockMap() { return blocks; } + FragmentMap &fragmentMap() { return fragments; } + + static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(it.n); } + + int nextCursorPosition(int position, QTextLayout::CursorMode mode) const; + int previousCursorPosition(int position, QTextLayout::CursorMode mode) const; + int leftCursorPosition(int position) const; + int rightCursorPosition(int position) const; + + void changeObjectFormat(QTextObject *group, int format); + + void setModified(bool m); + inline bool isModified() const { return modified; } + + inline QFont defaultFont() const { return formats.defaultFont(); } + inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); } + + void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false); + +private: + bool split(int pos); + bool unite(uint f); + + void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op); + int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command); + int remove_string(int pos, uint length, QTextUndoCommand::Operation op); + int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op); + + void insert_frame(QTextFrame *f); + void scan_frames(int pos, int charsRemoved, int charsAdded); + static void clearFrame(QTextFrame *f); + + void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op); + + bool wasUndoAvailable; + bool wasRedoAvailable; + +public: + void documentChange(int from, int length); + + inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); } + inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); } + + QTextFrame *frameAt(int pos) const; + QTextFrame *rootFrame() const; + + QTextObject *objectForIndex(int objectIndex) const; + QTextObject *objectForFormat(int formatIndex) const; + QTextObject *objectForFormat(const QTextFormat &f) const; + + QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1); + void deleteObject(QTextObject *object); + + QTextDocument *document() { return q_func(); } + const QTextDocument *document() const { return q_func(); } + + bool ensureMaximumBlockCount(); + +private: + QTextDocumentPrivate(const QTextDocumentPrivate& m); + QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m); + + void appendUndoItem(const QTextUndoCommand &c); + + void contentsChanged(); + + void compressPieceTable(); + + QString text; + uint unreachableCharacterCount; + + QVector undoStack; + bool undoEnabled; + int undoState; + int revision; + // position in undo stack of the last setModified(false) call + int modifiedState; + bool modified; + + int editBlock; + int editBlockCursorPosition; + int docChangeFrom; + int docChangeOldLength; + int docChangeLength; + bool framesDirty; + + QTextFormatCollection formats; + mutable QTextFrame *rtFrame; + QAbstractTextDocumentLayout *lout; + FragmentMap fragments; + BlockMap blocks; + int initialBlockCharFormatIndex; + + QList cursors; + QMap objects; + QMap resources; + QMap cachedResources; + QString defaultStyleSheet; + + int lastBlockCount; + +public: + QTextOption defaultTextOption; + Qt::CursorMoveStyle defaultCursorMoveStyle; +#ifndef QT_NO_CSSPARSER + QCss::StyleSheet parsedDefaultStyleSheet; +#endif + int maximumBlockCount; + uint needsEnsureMaximumBlockCount : 1; + uint inContentsChange : 1; + uint blockCursorAdjustment : 1; + QSizeF pageSize; + QString title; + QString url; + qreal indentWidth; + qreal documentMargin; + QUrl baseUrl; + + void mergeCachedResources(const QTextDocumentPrivate *priv); + + friend class QTextHtmlExporter; + friend class QTextCursor; +}; + +class QTextTable; +class QTextHtmlExporter +{ +public: + QTextHtmlExporter(const QTextDocument *_doc); + + enum ExportMode { + ExportEntireDocument, + ExportFragment + }; + + QString toHtml(const QByteArray &encoding, ExportMode mode = ExportEntireDocument); + +private: + enum StyleMode { EmitStyleTag, OmitStyleTag }; + enum FrameType { TextFrame, TableFrame, RootFrame }; + + void emitFrame(QTextFrame::Iterator frameIt); + void emitTextFrame(const QTextFrame *frame); + void emitBlock(const QTextBlock &block); + void emitTable(const QTextTable *table); + void emitFragment(const QTextFragment &fragment); + + void emitBlockAttributes(const QTextBlock &block); + bool emitCharFormatStyle(const QTextCharFormat &format); + void emitTextLength(const char *attribute, const QTextLength &length); + void emitAlignment(Qt::Alignment alignment); + void emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode = EmitStyleTag); + void emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right); + void emitAttribute(const char *attribute, const QString &value); + void emitFrameStyle(const QTextFrameFormat &format, FrameType frameType); + void emitBorderStyle(QTextFrameFormat::BorderStyle style); + void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy); + + void emitFontFamily(const QString &family); + + void emitBackgroundAttribute(const QTextFormat &format); + QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap); + + QString html; + QTextCharFormat defaultCharFormat; + const QTextDocument *doc; + bool fragmentMarkers; +}; + +QT_END_NAMESPACE + +#endif // QTEXTDOCUMENT_P_H diff --git a/Telegram/private/qtextengine_p.h b/Telegram/private/qtextengine_p.h new file mode 100644 index 000000000..ab13d6977 --- /dev/null +++ b/Telegram/private/qtextengine_p.h @@ -0,0 +1,721 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTENGINE_P_H +#define QTEXTENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qglobal.h" +#include "QtCore/qstring.h" +#include "QtCore/qvarlengtharray.h" +#include "QtCore/qnamespace.h" +#include "private/qtextlayout.h" +#include "private/qtextformat_p.h" +#include "private/qfont_p.h" +#include "QtCore/qvector.h" +#include "QtGui/qpaintengine.h" +#include "QtGui/qtextobject.h" +#include "QtGui/qtextoption.h" +#include "QtGui/qtextcursor.h" +#include "QtCore/qset.h" +#include "QtCore/qdebug.h" +#ifndef QT_BUILD_COMPAT_LIB +#include "private/qtextdocument_p.h" +#endif + +#include "private/qfixed_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QFontPrivate; +class QFontEngine; + +class QString; +class QPainter; + +class QAbstractTextDocumentLayout; + +typedef quint32 glyph_t; + +// this uses the same coordinate system as Qt, but a different one to freetype. +// * y is usually negative, and is equal to the ascent. +// * negative yoff means the following stuff is drawn higher up. +// the characters bounding rect is given by QRect(x,y,width,height), its advance by +// xoo and yoff +struct Q_GUI_EXPORT glyph_metrics_t +{ + inline glyph_metrics_t() + : x(100000), y(100000) {} + inline glyph_metrics_t(QFixed _x, QFixed _y, QFixed _width, QFixed _height, QFixed _xoff, QFixed _yoff) + : x(_x), + y(_y), + width(_width), + height(_height), + xoff(_xoff), + yoff(_yoff) + {} + QFixed x; + QFixed y; + QFixed width; + QFixed height; + QFixed xoff; + QFixed yoff; + + glyph_metrics_t transformed(const QTransform &xform) const; + inline bool isValid() const {return x != 100000 && y != 100000;} + + inline QFixed leftBearing() const + { + if (!isValid()) + return QFixed(); + + return x; + } + + inline QFixed rightBearing() const + { + if (!isValid()) + return QFixed(); + + return xoff - x - width; + } +}; +Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE); + +struct Q_AUTOTEST_EXPORT QScriptAnalysis +{ + enum Flags { + None = 0, + Lowercase = 1, + Uppercase = 2, + SmallCaps = 3, + LineOrParagraphSeparator = 4, + Space = 5, + SpaceTabOrObject = Space, + Tab = 6, + TabOrObject = Tab, + Object = 7 + }; + unsigned short script : 7; + unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61) + unsigned short flags : 3; + inline bool operator == (const QScriptAnalysis &other) const { + return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags; + } +}; +Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE); + +struct QGlyphJustification +{ + inline QGlyphJustification() + : type(0), nKashidas(0), space_18d6(0) + {} + + enum JustificationType { + JustifyNone, + JustifySpace, + JustifyKashida + }; + + uint type :2; + uint nKashidas : 6; // more do not make sense... + uint space_18d6 : 24; +}; +Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE); + +struct QGlyphAttributes { + uchar clusterStart : 1; + uchar dontPrint : 1; + uchar justification : 4; + uchar reserved : 2; +}; +Q_STATIC_ASSERT(sizeof(QGlyphAttributes) == 1); +Q_DECLARE_TYPEINFO(QGlyphAttributes, Q_PRIMITIVE_TYPE); + +struct QGlyphLayout +{ + enum { + SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint) + + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification) + }; + + // init to 0 not needed, done when shaping + QFixedPoint *offsets; // 8 bytes per element + glyph_t *glyphs; // 4 bytes per element + QFixed *advances; // 4 bytes per element + QGlyphJustification *justifications; // 4 bytes per element + QGlyphAttributes *attributes; // 1 byte per element + + int numGlyphs; + + inline QGlyphLayout() : numGlyphs(0) {} + + inline explicit QGlyphLayout(char *address, int totalGlyphs) + { + offsets = reinterpret_cast(address); + int offset = totalGlyphs * sizeof(QFixedPoint); + glyphs = reinterpret_cast(address + offset); + offset += totalGlyphs * sizeof(glyph_t); + advances = reinterpret_cast(address + offset); + offset += totalGlyphs * sizeof(QFixed); + justifications = reinterpret_cast(address + offset); + offset += totalGlyphs * sizeof(QGlyphJustification); + attributes = reinterpret_cast(address + offset); + numGlyphs = totalGlyphs; + } + + inline QGlyphLayout mid(int position, int n = -1) const { + QGlyphLayout copy = *this; + copy.glyphs += position; + copy.advances += position; + copy.offsets += position; + copy.justifications += position; + copy.attributes += position; + if (n == -1) + copy.numGlyphs -= position; + else + copy.numGlyphs = n; + return copy; + } + + inline QFixed effectiveAdvance(int item) const + { return (advances[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; } + + inline void clear(int first = 0, int last = -1) { + if (last == -1) + last = numGlyphs; + if (first == 0 && last == numGlyphs + && reinterpret_cast(offsets + numGlyphs) == reinterpret_cast(glyphs)) { + memset(offsets, 0, (numGlyphs * SpaceNeeded)); + } else { + const int num = last - first; + memset(offsets + first, 0, num * sizeof(QFixedPoint)); + memset(glyphs + first, 0, num * sizeof(glyph_t)); + memset(advances + first, 0, num * sizeof(QFixed)); + memset(justifications + first, 0, num * sizeof(QGlyphJustification)); + memset(attributes + first, 0, num * sizeof(QGlyphAttributes)); + } + } + + inline char *data() { + return reinterpret_cast(offsets); + } + + void grow(char *address, int totalGlyphs); +}; + +class QVarLengthGlyphLayoutArray : private QVarLengthArray, public QGlyphLayout +{ +private: + typedef QVarLengthArray Array; +public: + QVarLengthGlyphLayoutArray(int totalGlyphs) + : Array((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1) + , QGlyphLayout(reinterpret_cast(Array::data()), totalGlyphs) + { + memset(Array::data(), 0, Array::size() * sizeof(void *)); + } + + void resize(int totalGlyphs) + { + Array::resize((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1); + + *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast(Array::data()), totalGlyphs); + memset(Array::data(), 0, Array::size() * sizeof(void *)); + } +}; + +template struct QGlyphLayoutArray : public QGlyphLayout +{ +public: + QGlyphLayoutArray() + : QGlyphLayout(reinterpret_cast(buffer), N) + { + memset(buffer, 0, sizeof(buffer)); + } + +private: + void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1]; +}; + +struct QScriptItem; +/// Internal QTextItem +class QTextItemInt : public QTextItem +{ +public: + inline QTextItemInt() + : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0), + logClusters(0), f(0), fontEngine(0) + {} + QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); + QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe, + const QTextCharFormat &format = QTextCharFormat()); + + /// copy the structure items, adjusting the glyphs arrays to the right subarrays. + /// the width of the returned QTextItemInt is not adjusted, for speed reasons + QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const; + void initWithScriptItem(const QScriptItem &si); + + QFixed descent; + QFixed ascent; + QFixed width; + + RenderFlags flags; + bool justified; + QTextCharFormat::UnderlineStyle underlineStyle; + const QTextCharFormat charFormat; + int num_chars; + const QChar *chars; + const unsigned short *logClusters; + const QFont *f; + + QGlyphLayout glyphs; + QFontEngine *fontEngine; +}; + +struct Q_AUTOTEST_EXPORT QScriptItem +{ + inline QScriptItem() + : position(0), + num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1), + glyph_data_offset(0) {} + inline QScriptItem(int p, const QScriptAnalysis &a) + : position(p), analysis(a), + num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1), + glyph_data_offset(0) {} + + int position; + QScriptAnalysis analysis; + unsigned short num_glyphs; + QFixed descent; + QFixed ascent; + QFixed leading; + QFixed width; + int glyph_data_offset; + QFixed height() const { return ascent + descent; } +}; + + +Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE); + +typedef QVector QScriptItemArray; + +struct Q_AUTOTEST_EXPORT QScriptLine +{ + // created and filled in QTextLine::layout_helper + QScriptLine() + : from(0), trailingSpaces(0), length(0), + justified(0), gridfitted(0), + hasTrailingSpaces(0), leadingIncluded(0) {} + QFixed descent; + QFixed ascent; + QFixed leading; + QFixed x; + QFixed y; + QFixed width; + QFixed textWidth; + QFixed textAdvance; + int from; + unsigned short trailingSpaces; + signed int length : 28; + mutable uint justified : 1; + mutable uint gridfitted : 1; + uint hasTrailingSpaces : 1; + uint leadingIncluded : 1; + QFixed height() const { return ascent + descent + + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); } + QFixed base() const { return ascent; } + void setDefaultHeight(QTextEngine *eng); + void operator+=(const QScriptLine &other); +}; +Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE); + + +inline void QScriptLine::operator+=(const QScriptLine &other) +{ + leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent); + descent = qMax(descent, other.descent); + ascent = qMax(ascent, other.ascent); + textWidth += other.textWidth; + length += other.length; +} + +typedef QVector QScriptLineArray; + +class QFontPrivate; +class QTextFormatCollection; + +class Q_GUI_EXPORT QTextEngine { +public: + enum LayoutState { + LayoutEmpty, + InLayout, + LayoutFailed + }; + struct Q_GUI_EXPORT LayoutData { + LayoutData(const QString &str, void **stack_memory, int mem_size); + LayoutData(); + ~LayoutData(); + mutable QScriptItemArray items; + int allocated; + int available_glyphs; + void **memory; + unsigned short *logClustersPtr; + QGlyphLayout glyphLayout; + mutable int used; + uint hasBidi : 1; + uint layoutState : 2; + uint memory_on_stack : 1; + uint haveCharAttributes : 1; + QString string; + bool reallocate(int totalGlyphs); + }; + + struct ItemDecoration { + ItemDecoration() {} // for QVector, don't use + ItemDecoration(qreal x1, qreal x2, qreal y, const QPen &pen): + x1(x1), x2(x2), y(y), pen(pen) {} + + qreal x1; + qreal x2; + qreal y; + QPen pen; + }; + + typedef QVector ItemDecorationList; + + QTextEngine(); + QTextEngine(const QString &str, const QFont &f); + ~QTextEngine(); + + enum Mode { + WidthOnly = 0x07 + }; + + void invalidate(); + void clearLineData(); + + void validate() const; + void itemize() const; + + bool isRightToLeft() const; + static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder); + + const QCharAttributes *attributes() const; + + void shape(int item) const; + + void justify(const QScriptLine &si); + QFixed alignLine(const QScriptLine &line); + + QFixed width(int charFrom, int numChars) const; + glyph_metrics_t boundingBox(int from, int len) const; + glyph_metrics_t tightBoundingBox(int from, int len) const; + + int length(int item) const { + const QScriptItem &si = layoutData->items[item]; + int from = si.position; + item++; + return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from; + } + int length(const QScriptItem *si) const { + int end; + if (si + 1 < layoutData->items.constData()+ layoutData->items.size()) + end = (si+1)->position; + else + end = layoutData->string.length(); + return end - si->position; + } + + QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0, QFixed *leading = 0) const; + QFont font(const QScriptItem &si) const; + inline QFont font() const { return fnt; } + + /** + * Returns a pointer to an array of log clusters, offset at the script item. + * Each item in the array is a unsigned short. For each character in the original string there is an entry in the table + * so there is a one to one correlation in indexes between the original text and the index in the logcluster. + * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply + * that one glyph is used for more than one character. + * \sa glyphs() + */ + inline unsigned short *logClusters(const QScriptItem *si) const + { return layoutData->logClustersPtr+si->position; } + /** + * Returns an array of QGlyphLayout items, offset at the script item. + * Each item in the array matches one glyph in the text, storing the advance, position etc. + * The returned item's length equals to the number of available glyphs. This may be more + * than what was actually shaped. + * \sa logClusters() + */ + inline QGlyphLayout availableGlyphs(const QScriptItem *si) const { + return layoutData->glyphLayout.mid(si->glyph_data_offset); + } + /** + * Returns an array of QGlyphLayout items, offset at the script item. + * Each item in the array matches one glyph in the text, storing the advance, position etc. + * The returned item's length equals to the number of shaped glyphs. + * \sa logClusters() + */ + inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const { + return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs); + } + + inline bool ensureSpace(int nGlyphs) const { + if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs) + return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4); + return true; + } + + void freeMemory(); + + int findItem(int strPos, int firstItem = 0) const; + inline QTextFormatCollection *formatCollection() const { + if (block.docHandle()) + return block.docHandle()->formatCollection(); + return specialData ? specialData->formatCollection.data() : 0; + } + QTextCharFormat format(const QScriptItem *si) const; + inline QAbstractTextDocumentLayout *docLayout() const { + Q_ASSERT(block.docHandle()); + return block.docHandle()->document()->documentLayout(); + } + int formatIndex(const QScriptItem *si) const; + + /// returns the width of tab at index (in the tabs array) with the tab-start at position x + QFixed calculateTabWidth(int index, QFixed x) const; + + mutable QScriptLineArray lines; + +private: + struct FontEngineCache { + FontEngineCache(); + mutable QFontEngine *prevFontEngine; + mutable QFontEngine *prevScaledFontEngine; + mutable int prevScript; + mutable int prevPosition; + mutable int prevLength; + inline void reset() { + prevFontEngine = 0; + prevScaledFontEngine = 0; + prevScript = -1; + prevPosition = -1; + prevLength = -1; + } + }; + mutable FontEngineCache feCache; + +public: + QString text; + mutable QFont fnt; +#ifndef QT_NO_RAWFONT + QRawFont rawFont; +#endif + QTextBlock block; + + QTextOption option; + + QFixed minWidth; + QFixed maxWidth; + QPointF position; + uint ignoreBidi : 1; + uint cacheGlyphs : 1; + uint stackEngine : 1; + uint forceJustification : 1; + uint visualMovement : 1; + uint delayDecorations: 1; +#ifndef QT_NO_RAWFONT + uint useRawFont : 1; +#endif + + mutable LayoutData *layoutData; + + ItemDecorationList underlineList; + ItemDecorationList strikeOutList; + ItemDecorationList overlineList; + + inline bool visualCursorMovement() const + { return visualMovement || (block.docHandle() && block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle); } + + inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; } + inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); } + void setPreeditArea(int position, const QString &text); + + inline bool hasFormats() const + { return block.docHandle() || (specialData && !specialData->formats.isEmpty()); } + inline QVector formats() const + { return specialData ? specialData->formats : QVector(); } + void setFormats(const QVector &formats); + +private: + static void init(QTextEngine *e); + + struct SpecialData { + int preeditPosition; + QString preeditText; + QVector formats; + QVector resolvedFormats; + // only used when no docHandle is available + QScopedPointer formatCollection; + }; + SpecialData *specialData; + + void indexFormats(); + void resolveFormats() const; + +public: + bool atWordSeparator(int position) const; + + QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const; + + void shapeLine(const QScriptLine &line); + QFixed leadingSpaceWidth(const QScriptLine &line); + + QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos); + int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter); + int previousLogicalPosition(int oldPos) const; + int nextLogicalPosition(int oldPos) const; + int lineNumberForTextPosition(int pos); + int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op); + void insertionPointsForLine(int lineNum, QVector &insertionPoints); + void resetFontEngineCache(); + + void enableDelayDecorations(bool enable = true) { delayDecorations = enable; } + + void addUnderline(QPainter *painter, const QLineF &line); + void addStrikeOut(QPainter *painter, const QLineF &line); + void addOverline(QPainter *painter, const QLineF &line); + + void drawDecorations(QPainter *painter); + void clearDecorations(); + void adjustUnderlines(); + +private: + void addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList); + void adjustUnderlines(ItemDecorationList::iterator start, + ItemDecorationList::iterator end, + qreal underlinePos, qreal penWidth); + void drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList); + void setBoundary(int strPos) const; + void addRequiredBoundaries() const; + void shapeText(int item) const; +#ifdef QT_ENABLE_HARFBUZZ_NG + int shapeTextWithHarfbuzzNG(const QScriptItem &si, + const ushort *string, + int itemLength, + QFontEngine *fontEngine, + const QVector &itemBoundaries, + bool kerningEnabled, + bool hasLetterSpacing) const; +#endif + int shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector &itemBoundaries, bool kerningEnabled) const; + + int endOfLine(int lineNum); + int beginningOfLine(int lineNum); + int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start); +}; + +class Q_GUI_EXPORT QStackTextEngine : public QTextEngine { +public: + enum { MemSize = 256*40/sizeof(void *) }; + QStackTextEngine(const QString &string, const QFont &f); + LayoutData _layoutData; + void *_memory[MemSize]; +}; +Q_DECLARE_TYPEINFO(QTextEngine::ItemDecoration, Q_MOVABLE_TYPE); + +struct QTextLineItemIterator +{ + QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(), + const QTextLayout::FormatRange *_selection = 0); + + inline bool atEnd() const { return logicalItem >= nItems - 1; } + inline bool atBeginning() const { return logicalItem <= 0; } + QScriptItem &next(); + + bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const; + inline bool isOutsideSelection() const { + QFixed tmp1, tmp2; + return !getSelectionBounds(&tmp1, &tmp2); + } + + QTextEngine *eng; + + QFixed x; + const QScriptLine &line; + QScriptItem *si; + + const int lineNum; + const int lineEnd; + const int firstItem; + const int lastItem; + const int nItems; + int logicalItem; + int item; + int itemLength; + + int glyphsStart; + int glyphsEnd; + int itemStart; + int itemEnd; + + QFixed itemWidth; + + QVarLengthArray visualOrder; + + const QTextLayout::FormatRange *selection; +}; + +QT_END_NAMESPACE + +#endif // QTEXTENGINE_P_H diff --git a/Telegram/private/qtextformat_p.h b/Telegram/private/qtextformat_p.h new file mode 100644 index 000000000..45a432d2f --- /dev/null +++ b/Telegram/private/qtextformat_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTFORMAT_P_H +#define QTEXTFORMAT_P_H + +// +// 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. +// + +#include "QtGui/qtextformat.h" +#include "QtCore/qvector.h" + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QTextFormatCollection +{ +public: + QTextFormatCollection() {} + ~QTextFormatCollection(); + + QTextFormatCollection(const QTextFormatCollection &rhs); + QTextFormatCollection &operator=(const QTextFormatCollection &rhs); + + inline QTextFormat objectFormat(int objectIndex) const + { return format(objectFormatIndex(objectIndex)); } + inline void setObjectFormat(int objectIndex, const QTextFormat &format) + { setObjectFormatIndex(objectIndex, indexForFormat(format)); } + + int objectFormatIndex(int objectIndex) const; + void setObjectFormatIndex(int objectIndex, int formatIndex); + + int createObjectIndex(const QTextFormat &f); + + int indexForFormat(const QTextFormat &f); + bool hasFormatCached(const QTextFormat &format) const; + + QTextFormat format(int idx) const; + inline QTextBlockFormat blockFormat(int index) const + { return format(index).toBlockFormat(); } + inline QTextCharFormat charFormat(int index) const + { return format(index).toCharFormat(); } + inline QTextListFormat listFormat(int index) const + { return format(index).toListFormat(); } + inline QTextTableFormat tableFormat(int index) const + { return format(index).toTableFormat(); } + inline QTextImageFormat imageFormat(int index) const + { return format(index).toImageFormat(); } + + inline int numFormats() const { return formats.count(); } + + typedef QVector FormatVector; + + FormatVector formats; + QVector objFormats; + QMultiHash hashes; + + inline QFont defaultFont() const { return defaultFnt; } + void setDefaultFont(const QFont &f); + +private: + QFont defaultFnt; +}; + +QT_END_NAMESPACE + +#endif // QTEXTFORMAT_P_H diff --git a/Telegram/private/qtextlayout.h b/Telegram/private/qtextlayout.h new file mode 100644 index 000000000..aebf977b9 --- /dev/null +++ b/Telegram/private/qtextlayout.h @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTEXTLAYOUT_H +#define QTEXTLAYOUT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +class QTextEngine; +class QFont; +#ifndef QT_NO_RAWFONT +class QRawFont; +#endif +class QRect; +class QRegion; +class QTextFormat; +class QPalette; +class QPainter; + +class Q_GUI_EXPORT QTextInlineObject +{ +public: + QTextInlineObject(int i, QTextEngine *e) : itm(i), eng(e) {} + inline QTextInlineObject() : itm(0), eng(Q_NULLPTR) {} + inline bool isValid() const { return eng; } + + QRectF rect() const; + qreal width() const; + qreal ascent() const; + qreal descent() const; + qreal height() const; + + Qt::LayoutDirection textDirection() const; + + void setWidth(qreal w); + void setAscent(qreal a); + void setDescent(qreal d); + + int textPosition() const; + + int formatIndex() const; + QTextFormat format() const; + +private: + friend class QTextLayout; + int itm; + QTextEngine *eng; +}; + +class QPaintDevice; +class QTextFormat; +class QTextLine; +class QTextBlock; +class QTextOption; + +class Q_GUI_EXPORT QTextLayout +{ +public: + // does itemization + QTextLayout(); + QTextLayout(const QString& text); + QTextLayout(const QString& text, const QFont &font, QPaintDevice *paintdevice = Q_NULLPTR); + QTextLayout(const QTextBlock &b); + ~QTextLayout(); + + void setFont(const QFont &f); + QFont font() const; + +#ifndef QT_NO_RAWFONT + void setRawFont(const QRawFont &rawFont); +#endif + + void setText(const QString& string); + QString text() const; + + void setTextOption(const QTextOption &option); + const QTextOption &textOption() const; + + void setPreeditArea(int position, const QString &text); + int preeditAreaPosition() const; + QString preeditAreaText() const; + + struct FormatRange { + int start; + int length; + QTextCharFormat format; + + friend bool operator==(const FormatRange &lhs, const FormatRange &rhs) + { return lhs.start == rhs.start && lhs.length == rhs.length && lhs.format == rhs.format; } + friend bool operator!=(const FormatRange &lhs, const FormatRange &rhs) + { return !operator==(lhs, rhs); } + }; +#if QT_DEPRECATED_SINCE(5, 6) + QT_DEPRECATED_X("Use setFormats()") void setAdditionalFormats(const QList &overrides); + QT_DEPRECATED_X("Use formats()") QList additionalFormats() const; + QT_DEPRECATED_X("Use clearFormats()") void clearAdditionalFormats(); +#endif + void setFormats(const QVector &overrides); + QVector formats() const; + void clearFormats(); + + void setCacheEnabled(bool enable); + bool cacheEnabled() const; + + void setCursorMoveStyle(Qt::CursorMoveStyle style); + Qt::CursorMoveStyle cursorMoveStyle() const; + + void beginLayout(); + void endLayout(); + void clearLayout(); + + QTextLine createLine(); + + int lineCount() const; + QTextLine lineAt(int i) const; + QTextLine lineForTextPosition(int pos) const; + + enum CursorMode { + SkipCharacters, + SkipWords + }; + bool isValidCursorPosition(int pos) const; + int nextCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; + int previousCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; + int leftCursorPosition(int oldPos) const; + int rightCursorPosition(int oldPos) const; + + void draw(QPainter *p, const QPointF &pos, const QVector &selections = QVector(), + const QRectF &clip = QRectF()) const; + void drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const; + void drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const; + + QPointF position() const; + void setPosition(const QPointF &p); + + QRectF boundingRect() const; + + qreal minimumWidth() const; + qreal maximumWidth() const; + +#if !defined(QT_NO_RAWFONT) + QList glyphRuns(int from = -1, int length = -1) const; +#endif + + QTextEngine *engine() const { return d; } + void setFlags(int flags); + QTextLayout(QTextEngine *e) : d(e) {} +private: + Q_DISABLE_COPY(QTextLayout) + + friend class QPainter; + friend class QGraphicsSimpleTextItemPrivate; + friend class QGraphicsSimpleTextItem; + friend void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *, const QString& str, + QRectF *brect, int tabstops, int* tabarray, int tabarraylen, + QPainter *painter); + QTextEngine *d; +}; +Q_DECLARE_TYPEINFO(QTextLayout::FormatRange, Q_RELOCATABLE_TYPE); + + +class Q_GUI_EXPORT QTextLine +{ +public: + inline QTextLine() : index(0), eng(Q_NULLPTR) {} + inline bool isValid() const { return eng; } + + QRectF rect() const; + qreal x() const; + qreal y() const; + qreal width() const; + qreal ascent() const; + qreal descent() const; + qreal height() const; + qreal leading() const; + + void setLeadingIncluded(bool included); + bool leadingIncluded() const; + + qreal naturalTextWidth() const; + qreal horizontalAdvance() const; + QRectF naturalTextRect() const; + + enum Edge { + Leading, + Trailing + }; + enum CursorPosition { + CursorBetweenCharacters, + CursorOnCharacter + }; + + /* cursorPos gets set to the valid position */ + qreal cursorToX(int *cursorPos, Edge edge = Leading) const; + inline qreal cursorToX(int cursorPos, Edge edge = Leading) const { return cursorToX(&cursorPos, edge); } + int xToCursor(qreal x, CursorPosition = CursorBetweenCharacters) const; + + void setLineWidth(qreal width); + void setNumColumns(int columns); + void setNumColumns(int columns, qreal alignmentWidth); + + void setPosition(const QPointF &pos); + QPointF position() const; + + int textStart() const; + int textLength() const; + + int lineNumber() const { return index; } + + void draw(QPainter *p, const QPointF &point, const QTextLayout::FormatRange *selection = Q_NULLPTR) const; + +#if !defined(QT_NO_RAWFONT) + QList glyphRuns(int from = -1, int length = -1) const; +#endif + +private: + QTextLine(int line, QTextEngine *e) : index(line), eng(e) {} + void layout_helper(int numGlyphs); + + friend class QTextLayout; + friend class QTextFragment; + int index; + QTextEngine *eng; +}; + +QT_END_NAMESPACE + +#endif // QTEXTLAYOUT_H diff --git a/Telegram/private/qtools_p.h b/Telegram/private/qtools_p.h new file mode 100644 index 000000000..5ec153c81 --- /dev/null +++ b/Telegram/private/qtools_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTOOLS_P_H +#define QTOOLS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qglobal.h" +#include + +QT_BEGIN_NAMESPACE + +namespace QtMiscUtils { +Q_DECL_CONSTEXPR inline char toHexUpper(uint value) Q_DECL_NOTHROW +{ + return "0123456789ABCDEF"[value & 0xF]; +} + +Q_DECL_CONSTEXPR inline char toHexLower(uint value) Q_DECL_NOTHROW +{ + return "0123456789abcdef"[value & 0xF]; +} + +Q_DECL_CONSTEXPR inline int fromHex(uint c) Q_DECL_NOTHROW +{ + return ((c >= '0') && (c <= '9')) ? int(c - '0') : + ((c >= 'A') && (c <= 'F')) ? int(c - 'A' + 10) : + ((c >= 'a') && (c <= 'f')) ? int(c - 'a' + 10) : + /* otherwise */ -1; +} + +Q_DECL_CONSTEXPR inline char toOct(uint value) Q_DECL_NOTHROW +{ + return '0' + char(value & 0x7); +} + +Q_DECL_CONSTEXPR inline int fromOct(uint c) Q_DECL_NOTHROW +{ + return ((c >= '0') && (c <= '7')) ? int(c - '0') : -1; +} +} + +// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size. +enum { + MaxAllocSize = (1 << (std::numeric_limits::digits - 1)) - 1 +}; + +// implemented in qbytearray.cpp +int Q_CORE_EXPORT qAllocMore(int alloc, int extra) Q_DECL_NOTHROW; + +QT_END_NAMESPACE + +#endif // QTOOLS_P_H diff --git a/Telegram/private/qunicodetools_p.h b/Telegram/private/qunicodetools_p.h new file mode 100644 index 000000000..5cde18865 --- /dev/null +++ b/Telegram/private/qunicodetools_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUNICODETOOLS_P_H +#define QUNICODETOOLS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +struct QCharAttributes +{ + uchar graphemeBoundary : 1; + uchar wordBreak : 1; + uchar sentenceBoundary : 1; + uchar lineBreak : 1; + uchar whiteSpace : 1; + uchar wordStart : 1; + uchar wordEnd : 1; + uchar mandatoryBreak : 1; +}; +Q_DECLARE_TYPEINFO(QCharAttributes, Q_PRIMITIVE_TYPE); + +namespace QUnicodeTools { + +// ### temporary +struct ScriptItem +{ + int position; + int script; +}; + +} // namespace QUnicodeTools +Q_DECLARE_TYPEINFO(QUnicodeTools::ScriptItem, Q_PRIMITIVE_TYPE); +namespace QUnicodeTools { + +enum CharAttributeOption { + GraphemeBreaks = 0x01, + WordBreaks = 0x02, + SentenceBreaks = 0x04, + LineBreaks = 0x08, + WhiteSpaces = 0x10, + DefaultOptionsCompat = GraphemeBreaks | LineBreaks | WhiteSpaces, // ### remove + + DontClearAttributes = 0x1000 +}; +Q_DECLARE_FLAGS(CharAttributeOptions, CharAttributeOption) + +// attributes buffer has to have a length of string length + 1 +Q_CORE_EXPORT void initCharAttributes(const ushort *string, int length, + const ScriptItem *items, int numItems, + QCharAttributes *attributes, CharAttributeOptions options = DefaultOptionsCompat); + + +Q_CORE_EXPORT void initScripts(const ushort *string, int length, uchar *scripts); + +} // namespace QUnicodeTools + +QT_END_NAMESPACE + +#endif // QUNICODETOOLS_P_H