📄 qtextdocumentlayout.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qtextdocumentlayout_p.h"#include "qtextdocument_p.h"#include "qtextimagehandler_p.h"#include "qtexttable.h"#include "qtextlist.h"#include "qtextengine_p.h"#include "private/qcssutil_p.h"#include "private/qmath_p.h"#include "qabstracttextdocumentlayout_p.h"#include "qcssparser_p.h"#include <qpainter.h>#include <qrect.h>#include <qpalette.h>#include <qdebug.h>#include <qvarlengtharray.h>#include <limits.h>#include <qstyle.h>#include <qbasictimer.h>// #define LAYOUT_DEBUG#ifdef LAYOUT_DEBUG#define LDEBUG qDebug()#define INC_INDENT debug_indent += " "#define DEC_INDENT debug_indent = debug_indent.left(debug_indent.length()-2)#else#define LDEBUG if(0) qDebug()#define INC_INDENT do {} while(0)#define DEC_INDENT do {} while(0)#endif// ################ should probably add frameFormatChange notification!struct QLayoutStruct;class QTextFrameData : public QTextFrameLayoutData{public: QTextFrameData(); // relative to parent frame QFixedPoint position; QFixedSize size; // contents starts at (margin+border/margin+border) QFixed topMargin; QFixed bottomMargin; QFixed leftMargin; QFixed rightMargin; QFixed border; QFixed padding; // contents width includes padding (as we need to treat this on a per cell basis for tables) QFixed contentsWidth; QFixed contentsHeight; QFixed oldContentsWidth; // accumulated margins QFixed effectiveTopMargin; QFixed effectiveBottomMargin; QFixed minimumWidth; QFixed maximumWidth; QLayoutStruct *currentLayoutStruct; bool sizeDirty; bool layoutDirty; QList<QPointer<QTextFrame> > floats;};QTextFrameData::QTextFrameData() : maximumWidth(QFIXED_MAX), currentLayoutStruct(0), sizeDirty(true), layoutDirty(true){}struct QLayoutStruct { QLayoutStruct() : maximumWidth(QFIXED_MAX), fullLayout(false) {} QTextFrame *frame; QFixed x_left; QFixed x_right; QFixed frameY; // absolute y position of the current frame QFixed y; // always relative to the current frame QFixed contentsWidth; QFixed minimumWidth; QFixed maximumWidth; bool fullLayout; QList<QTextFrame *> pendingFloats; QFixed pageHeight; QFixed pageBottom; QFixed pageTopMargin; QFixed pageBottomMargin; QRectF updateRect; inline QFixed absoluteY() const { return frameY + y; } inline int currentPage() const { return pageHeight == 0 ? 0 : (absoluteY() / pageHeight).truncate(); } inline void newPage() { if (pageHeight == QFIXED_MAX) return; pageBottom += pageHeight; y = pageBottom - pageHeight + pageBottomMargin + pageTopMargin - frameY; }};class QTextTableData : public QTextFrameData{public: QFixed cellSpacing, cellPadding; QVector<QFixed> minWidths; QVector<QFixed> maxWidths; QVector<QFixed> widths; QVector<QFixed> heights; QVector<QFixed> columnPositions; QVector<QFixed> rowPositions; QVector<QFixed> cellVerticalOffsets; QFixed headerHeight; // maps from cell index (row + col * rowCount) to child frames belonging to // the specific cell QMultiHash<int, QTextFrame *> childFrameMap; inline QFixed cellWidth(int column, int colspan) const { return columnPositions.at(column + colspan - 1) + widths.at(column + colspan - 1) - columnPositions.at(column) - 2 * cellPadding; } inline void calcRowPosition(int row) { if (row > 0) rowPositions[row] = rowPositions.at(row - 1) + heights.at(row - 1) + border + cellSpacing + border; } QRectF cellRect(const QTextTableCell &cell) const; inline QFixedPoint cellPosition(int row, int col) const { return QFixedPoint(columnPositions.at(col) + cellPadding, rowPositions.at(row) + cellPadding + cellVerticalOffsets.at(col + row * widths.size())); } inline QFixedPoint cellPosition(const QTextTableCell &cell) const { return cellPosition(cell.row(), cell.column()); } void updateTableSize();};static QTextFrameData *createData(QTextFrame *f){ QTextFrameData *data; if (qobject_cast<QTextTable *>(f)) data = new QTextTableData; else data = new QTextFrameData; f->setLayoutData(data); return data;}static inline QTextFrameData *data(QTextFrame *f){ QTextFrameData *data = static_cast<QTextFrameData *>(f->layoutData()); if (!data) data = createData(f); return data;}static bool isFrameFromInlineObject(QTextFrame *f){ return f->firstPosition() > f->lastPosition();}void QTextTableData::updateTableSize(){ const QFixed effectiveTopMargin = this->topMargin + border + padding; const QFixed effectiveBottomMargin = this->bottomMargin + border + padding; const QFixed effectiveLeftMargin = this->leftMargin + border + padding; const QFixed effectiveRightMargin = this->rightMargin + border + padding; size.height = contentsHeight == -1 ? rowPositions.last() + heights.last() + padding + border + cellSpacing + effectiveBottomMargin : effectiveTopMargin + contentsHeight + effectiveBottomMargin; size.width = effectiveLeftMargin + contentsWidth + effectiveRightMargin;}QRectF QTextTableData::cellRect(const QTextTableCell &cell) const{ const int row = cell.row(); const int rowSpan = cell.rowSpan(); const int column = cell.column(); const int colSpan = cell.columnSpan(); return QRectF(columnPositions.at(column).toReal(), rowPositions.at(row).toReal(), (columnPositions.at(column + colSpan - 1) + widths.at(column + colSpan - 1) - columnPositions.at(column)).toReal(), (rowPositions.at(row + rowSpan - 1) + heights.at(row + rowSpan - 1) - rowPositions.at(row)).toReal());}static inline bool isEmptyBlockBeforeTable(const QTextBlock &block, const QTextFrame::Iterator &nextIt){ QTextBlockFormat format = block.blockFormat(); return !nextIt.atEnd() && qobject_cast<QTextTable *>(nextIt.currentFrame()) && block.isValid() && block.length() == 1 && !format.hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth) && !format.hasProperty(QTextFormat::BackgroundBrush) && nextIt.currentFrame()->firstPosition() == block.position() + 1 ;}static inline bool isEmptyBlockBeforeTable(QTextFrame::Iterator it){ QTextFrame::Iterator next = it; ++next; return it.currentFrame() == 0 && isEmptyBlockBeforeTable(it.currentBlock(), next);}static inline bool isEmptyBlockAfterTable(const QTextBlock &block, const QTextFrame *lastFrame){ return qobject_cast<const QTextTable *>(lastFrame) && block.isValid() && block.length() == 1 && lastFrame->lastPosition() == block.position() - 1 ;}static inline bool isLineSeparatorBlockAfterTable(const QTextBlock &block, const QTextFrame *lastFrame){ return qobject_cast<const QTextTable *>(lastFrame) && block.isValid() && block.length() > 1 && block.text().at(0) == QChar::LineSeparator && lastFrame->lastPosition() == block.position() - 1 ;}/*Optimisation strategies:HTML layout:* Distinguish between normal and special flow. For normal flow the condition: y1 > y2 holds for all blocks with b1.key() > b2.key().* Special flow is: floats, table cells* Normal flow within table cells. Tables (not cells) are part of the normal flow.* If blocks grows/shrinks in height and extends over whole page width at the end, move following blocks.* If height doesn't change, no need to do anythingTable cells:* If minWidth of cell changes, recalculate table width, relayout if needed.* What about maxWidth when doing auto layout?Floats:* need fixed or proportional width, otherwise don't float!* On width/height change relayout surrounding paragraphs.Document width change:* full relayout neededFloat handling:* Floats are specified by a special format object.* currently only floating images are implemented.*//* On the table layouting: +---[ table border ]------------------------- | [ cell spacing ] | +------[ cell border ]-----+ +-------- | | | | | | | | | | | rowPositions[i] and columnPositions[i] point at the cell content position. So for example the left border is drawn at x = columnPositions[i] - fd->border and similar for y.*/enum { TextIndentValue = 40};struct QCheckPoint{ QFixed y; QFixed frameY; // absolute y position of the current frame int positionInFrame; QFixed minimumWidth; QFixed maximumWidth; QFixed contentsWidth;};Q_DECLARE_TYPEINFO(QCheckPoint, Q_PRIMITIVE_TYPE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -