src/gui/text/qtextdocumentlayout.cpp
changeset 33 3e2da88830cd
parent 22 79de32ba3296
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
    77 
    77 
    78 Q_GUI_EXPORT extern int qt_defaultDpi();
    78 Q_GUI_EXPORT extern int qt_defaultDpi();
    79 
    79 
    80 // ################ should probably add frameFormatChange notification!
    80 // ################ should probably add frameFormatChange notification!
    81 
    81 
    82 struct QLayoutStruct;
    82 struct QTextLayoutStruct;
    83 
    83 
    84 class QTextFrameData : public QTextFrameLayoutData
    84 class QTextFrameData : public QTextFrameLayoutData
    85 {
    85 {
    86 public:
    86 public:
    87     QTextFrameData();
    87     QTextFrameData();
   107     QFixed effectiveBottomMargin;
   107     QFixed effectiveBottomMargin;
   108 
   108 
   109     QFixed minimumWidth;
   109     QFixed minimumWidth;
   110     QFixed maximumWidth;
   110     QFixed maximumWidth;
   111 
   111 
   112     QLayoutStruct *currentLayoutStruct;
   112     QTextLayoutStruct *currentLayoutStruct;
   113 
   113 
   114     bool sizeDirty;
   114     bool sizeDirty;
   115     bool layoutDirty;
   115     bool layoutDirty;
   116 
   116 
   117     QList<QPointer<QTextFrame> > floats;
   117     QList<QPointer<QTextFrame> > floats;
   121     : maximumWidth(QFIXED_MAX),
   121     : maximumWidth(QFIXED_MAX),
   122       currentLayoutStruct(0), sizeDirty(true), layoutDirty(true)
   122       currentLayoutStruct(0), sizeDirty(true), layoutDirty(true)
   123 {
   123 {
   124 }
   124 }
   125 
   125 
   126 struct QLayoutStruct {
   126 struct QTextLayoutStruct {
   127     QLayoutStruct() : maximumWidth(QFIXED_MAX), fullLayout(false)
   127     QTextLayoutStruct() : maximumWidth(QFIXED_MAX), fullLayout(false)
   128     {}
   128     {}
   129     QTextFrame *frame;
   129     QTextFrame *frame;
   130     QFixed x_left;
   130     QFixed x_left;
   131     QFixed x_right;
   131     QFixed x_right;
   132     QFixed frameY; // absolute y position of the current frame
   132     QFixed frameY; // absolute y position of the current frame
   475     HitPoint hitTest(QTextFrame::Iterator it, HitPoint hit, const QFixedPoint &p,
   475     HitPoint hitTest(QTextFrame::Iterator it, HitPoint hit, const QFixedPoint &p,
   476                      int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
   476                      int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
   477     HitPoint hitTest(QTextTable *table, const QFixedPoint &point, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
   477     HitPoint hitTest(QTextTable *table, const QFixedPoint &point, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
   478     HitPoint hitTest(QTextBlock bl, const QFixedPoint &point, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
   478     HitPoint hitTest(QTextBlock bl, const QFixedPoint &point, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
   479 
   479 
   480     QLayoutStruct layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
   480     QTextLayoutStruct layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
   481                             int layoutFrom, int layoutTo, QTextTableData *tableData, QFixed absoluteTableY,
   481                                  int layoutFrom, int layoutTo, QTextTableData *tableData, QFixed absoluteTableY,
   482                             bool withPageBreaks);
   482                                  bool withPageBreaks);
   483     void setCellPosition(QTextTable *t, const QTextTableCell &cell, const QPointF &pos);
   483     void setCellPosition(QTextTable *t, const QTextTableCell &cell, const QPointF &pos);
   484     QRectF layoutTable(QTextTable *t, int layoutFrom, int layoutTo, QFixed parentY);
   484     QRectF layoutTable(QTextTable *t, int layoutFrom, int layoutTo, QFixed parentY);
   485 
   485 
   486     void positionFloat(QTextFrame *frame, QTextLine *currentLine = 0);
   486     void positionFloat(QTextFrame *frame, QTextLine *currentLine = 0);
   487 
   487 
   488     // calls the next one
   488     // calls the next one
   489     QRectF layoutFrame(QTextFrame *f, int layoutFrom, int layoutTo, QFixed parentY = 0);
   489     QRectF layoutFrame(QTextFrame *f, int layoutFrom, int layoutTo, QFixed parentY = 0);
   490     QRectF layoutFrame(QTextFrame *f, int layoutFrom, int layoutTo, QFixed frameWidth, QFixed frameHeight, QFixed parentY = 0);
   490     QRectF layoutFrame(QTextFrame *f, int layoutFrom, int layoutTo, QFixed frameWidth, QFixed frameHeight, QFixed parentY = 0);
   491 
   491 
   492     void layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat,
   492     void layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat,
   493                      QLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat);
   493                      QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat);
   494     void layoutFlow(QTextFrame::Iterator it, QLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, QFixed width = 0);
   494     void layoutFlow(QTextFrame::Iterator it, QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, QFixed width = 0);
   495     void pageBreakInsideTable(QTextTable *table, QLayoutStruct *layoutStruct);
   495     void pageBreakInsideTable(QTextTable *table, QTextLayoutStruct *layoutStruct);
   496 
   496 
   497 
   497 
   498     void floatMargins(const QFixed &y, const QLayoutStruct *layoutStruct, QFixed *left, QFixed *right) const;
   498     void floatMargins(const QFixed &y, const QTextLayoutStruct *layoutStruct, QFixed *left, QFixed *right) const;
   499     QFixed findY(QFixed yFrom, const QLayoutStruct *layoutStruct, QFixed requiredWidth) const;
   499     QFixed findY(QFixed yFrom, const QTextLayoutStruct *layoutStruct, QFixed requiredWidth) const;
   500 
   500 
   501     QVector<QCheckPoint> checkPoints;
   501     QVector<QCheckPoint> checkPoints;
   502 
   502 
   503     QTextFrame::Iterator frameIteratorForYPosition(QFixed y) const;
   503     QTextFrame::Iterator frameIteratorForYPosition(QFixed y) const;
   504     QTextFrame::Iterator frameIteratorForTextPosition(int position) const;
   504     QTextFrame::Iterator frameIteratorForTextPosition(int position) const;
  1367     if (layout->lineCount() == 0)
  1367     if (layout->lineCount() == 0)
  1368         return;
  1368         return;
  1369     QTextLine firstLine = layout->lineAt(0);
  1369     QTextLine firstLine = layout->lineAt(0);
  1370     Q_ASSERT(firstLine.isValid());
  1370     Q_ASSERT(firstLine.isValid());
  1371     QPointF pos = (offset + layout->position()).toPoint();
  1371     QPointF pos = (offset + layout->position()).toPoint();
  1372     Qt::LayoutDirection dir = docPrivate->defaultTextOption.textDirection();
  1372     Qt::LayoutDirection dir = bl.textDirection();
  1373     if (blockFormat.hasProperty(QTextFormat::LayoutDirection))
       
  1374         dir = blockFormat.layoutDirection();
       
  1375     {
  1373     {
  1376         QRectF textRect = firstLine.naturalTextRect();
  1374         QRectF textRect = firstLine.naturalTextRect();
  1377         pos += textRect.topLeft().toPoint();
  1375         pos += textRect.topLeft().toPoint();
  1378         if (dir == Qt::RightToLeft)
  1376         if (dir == Qt::RightToLeft)
  1379             pos.rx() += textRect.width();
  1377             pos.rx() += textRect.width();
  1485 static QFixed firstChildPos(const QTextFrame *f)
  1483 static QFixed firstChildPos(const QTextFrame *f)
  1486 {
  1484 {
  1487     return flowPosition(f->begin());
  1485     return flowPosition(f->begin());
  1488 }
  1486 }
  1489 
  1487 
  1490 QLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
  1488 QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
  1491                                                     int layoutFrom, int layoutTo, QTextTableData *td,
  1489                                                         int layoutFrom, int layoutTo, QTextTableData *td,
  1492                                                     QFixed absoluteTableY, bool withPageBreaks)
  1490                                                         QFixed absoluteTableY, bool withPageBreaks)
  1493 {
  1491 {
  1494     LDEBUG << "layoutCell";
  1492     LDEBUG << "layoutCell";
  1495     QLayoutStruct layoutStruct;
  1493     QTextLayoutStruct layoutStruct;
  1496     layoutStruct.frame = t;
  1494     layoutStruct.frame = t;
  1497     layoutStruct.minimumWidth = 0;
  1495     layoutStruct.minimumWidth = 0;
  1498     layoutStruct.maximumWidth = QFIXED_MAX;
  1496     layoutStruct.maximumWidth = QFIXED_MAX;
  1499     layoutStruct.y = 0;
  1497     layoutStruct.y = 0;
  1500 
  1498 
  1639             const QFixed widthPadding = leftPadding + rightPadding;
  1637             const QFixed widthPadding = leftPadding + rightPadding;
  1640 
  1638 
  1641             // to figure out the min and the max width lay out the cell at
  1639             // to figure out the min and the max width lay out the cell at
  1642             // maximum width. otherwise the maxwidth calculation sometimes
  1640             // maximum width. otherwise the maxwidth calculation sometimes
  1643             // returns wrong values
  1641             // returns wrong values
  1644             QLayoutStruct layoutStruct = layoutCell(table, cell, QFIXED_MAX, layoutFrom,
  1642             QTextLayoutStruct layoutStruct = layoutCell(table, cell, QFIXED_MAX, layoutFrom,
  1645                                                     layoutTo, td, absoluteTableY,
  1643                                                         layoutTo, td, absoluteTableY,
  1646                                                     /*withPageBreaks =*/false);
  1644                                                         /*withPageBreaks =*/false);
  1647 
  1645 
  1648             // distribute the minimum width over all columns the cell spans
  1646             // distribute the minimum width over all columns the cell spans
  1649             QFixed widthToDistribute = layoutStruct.minimumWidth + widthPadding;
  1647             QFixed widthToDistribute = layoutStruct.minimumWidth + widthPadding;
  1650             for (int n = 0; n < cspan; ++n) {
  1648             for (int n = 0; n < cspan; ++n) {
  1651                 const int col = i + n;
  1649                 const int col = i + n;
  1866             const QFixed widthPadding = leftPadding + rightPadding;
  1864             const QFixed widthPadding = leftPadding + rightPadding;
  1867 
  1865 
  1868             ++rowCellCount;
  1866             ++rowCellCount;
  1869 
  1867 
  1870             const QFixed width = td->cellWidth(c, cspan) - widthPadding;
  1868             const QFixed width = td->cellWidth(c, cspan) - widthPadding;
  1871             QLayoutStruct layoutStruct = layoutCell(table, cell, width,
  1869             QTextLayoutStruct layoutStruct = layoutCell(table, cell, width,
  1872                                                     layoutFrom, layoutTo,
  1870                                                        layoutFrom, layoutTo,
  1873                                                     td, absoluteTableY,
  1871                                                        td, absoluteTableY,
  1874                                                     /*withPageBreaks =*/true);
  1872                                                        /*withPageBreaks =*/true);
  1875 
  1873 
  1876             const QFixed height = layoutStruct.y + bottomPadding + topPadding;
  1874             const QFixed height = layoutStruct.y + bottomPadding + topPadding;
  1877 
  1875 
  1878             if (rspan > 1)
  1876             if (rspan > 1)
  1879                 heightToDistribute[c] = height + dropDistance;
  1877                 heightToDistribute[c] = height + dropDistance;
  1974     QTextFrame *parent = frame->parentFrame();
  1972     QTextFrame *parent = frame->parentFrame();
  1975     Q_ASSERT(parent);
  1973     Q_ASSERT(parent);
  1976     QTextFrameData *pd = data(parent);
  1974     QTextFrameData *pd = data(parent);
  1977     Q_ASSERT(pd && pd->currentLayoutStruct);
  1975     Q_ASSERT(pd && pd->currentLayoutStruct);
  1978 
  1976 
  1979     QLayoutStruct *layoutStruct = pd->currentLayoutStruct;
  1977     QTextLayoutStruct *layoutStruct = pd->currentLayoutStruct;
  1980 
  1978 
  1981     if (!pd->floats.contains(frame))
  1979     if (!pd->floats.contains(frame))
  1982         pd->floats.append(frame);
  1980         pd->floats.append(frame);
  1983     fd->layoutDirty = true;
  1981     fd->layoutDirty = true;
  1984     Q_ASSERT(!fd->sizeDirty);
  1982     Q_ASSERT(!fd->sizeDirty);
  2114     // set fd->contentsWidth temporarily, so that layoutFrame for the children
  2112     // set fd->contentsWidth temporarily, so that layoutFrame for the children
  2115     // picks the right width. We'll initialize it properly at the end of this
  2113     // picks the right width. We'll initialize it properly at the end of this
  2116     // function.
  2114     // function.
  2117     fd->contentsWidth = newContentsWidth;
  2115     fd->contentsWidth = newContentsWidth;
  2118 
  2116 
  2119     QLayoutStruct layoutStruct;
  2117     QTextLayoutStruct layoutStruct;
  2120     layoutStruct.frame = f;
  2118     layoutStruct.frame = f;
  2121     layoutStruct.x_left = fd->leftMargin + fd->border + fd->padding;
  2119     layoutStruct.x_left = fd->leftMargin + fd->border + fd->padding;
  2122     layoutStruct.x_right = layoutStruct.x_left + newContentsWidth;
  2120     layoutStruct.x_right = layoutStruct.x_left + newContentsWidth;
  2123     layoutStruct.y = fd->topMargin + fd->border + fd->padding;
  2121     layoutStruct.y = fd->topMargin + fd->border + fd->padding;
  2124     layoutStruct.frameY = parentY + fd->position.y;
  2122     layoutStruct.frameY = parentY + fd->position.y;
  2177     if (layoutStruct.updateRectForFloats.isValid())
  2175     if (layoutStruct.updateRectForFloats.isValid())
  2178         layoutStruct.updateRect |= layoutStruct.updateRectForFloats;
  2176         layoutStruct.updateRect |= layoutStruct.updateRectForFloats;
  2179     return layoutStruct.updateRect;
  2177     return layoutStruct.updateRect;
  2180 }
  2178 }
  2181 
  2179 
  2182 void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QLayoutStruct *layoutStruct,
  2180 void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayoutStruct *layoutStruct,
  2183                                             int layoutFrom, int layoutTo, QFixed width)
  2181                                             int layoutFrom, int layoutTo, QFixed width)
  2184 {
  2182 {
  2185     LDEBUG << "layoutFlow from=" << layoutFrom << "to=" << layoutTo;
  2183     LDEBUG << "layoutFlow from=" << layoutFrom << "to=" << layoutTo;
  2186     QTextFrameData *fd = data(layoutStruct->frame);
  2184     QTextFrameData *fd = data(layoutStruct->frame);
  2187 
  2185 
  2507 
  2505 
  2508     fd->currentLayoutStruct = 0;
  2506     fd->currentLayoutStruct = 0;
  2509 }
  2507 }
  2510 
  2508 
  2511 void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat,
  2509 void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat,
  2512                                              QLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat)
  2510                                              QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat)
  2513 {
  2511 {
  2514     Q_Q(QTextDocumentLayout);
  2512     Q_Q(QTextDocumentLayout);
  2515 
  2513 
  2516     QTextLayout *tl = bl.layout();
  2514     QTextLayout *tl = bl.layout();
  2517     const int blockLength = bl.length();
  2515     const int blockLength = bl.length();
  2528         layoutStruct->y += QFixed::fromReal(margin);
  2526         layoutStruct->y += QFixed::fromReal(margin);
  2529     }
  2527     }
  2530 
  2528 
  2531     //QTextFrameData *fd = data(layoutStruct->frame);
  2529     //QTextFrameData *fd = data(layoutStruct->frame);
  2532 
  2530 
  2533     Qt::LayoutDirection dir = docPrivate->defaultTextOption.textDirection();
  2531     Qt::LayoutDirection dir = bl.textDirection();
  2534     if (blockFormat.hasProperty(QTextFormat::LayoutDirection))
       
  2535         dir = blockFormat.layoutDirection();
       
  2536 
  2532 
  2537     QFixed extraMargin;
  2533     QFixed extraMargin;
  2538     if (docPrivate->defaultTextOption.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {
  2534     if (docPrivate->defaultTextOption.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {
  2539         QFontMetricsF fm(bl.charFormat().font());
  2535         QFontMetricsF fm(bl.charFormat().font());
  2540         extraMargin = QFixed::fromReal(fm.width(QChar(QChar(0x21B5))));
  2536         extraMargin = QFixed::fromReal(fm.width(QChar(QChar(0x21B5))));
  2716         else
  2712         else
  2717             layoutStruct->maximumWidth = qMax(layoutStruct->maximumWidth, maxW);
  2713             layoutStruct->maximumWidth = qMax(layoutStruct->maximumWidth, maxW);
  2718     }
  2714     }
  2719 }
  2715 }
  2720 
  2716 
  2721 void QTextDocumentLayoutPrivate::floatMargins(const QFixed &y, const QLayoutStruct *layoutStruct,
  2717 void QTextDocumentLayoutPrivate::floatMargins(const QFixed &y, const QTextLayoutStruct *layoutStruct,
  2722                                               QFixed *left, QFixed *right) const
  2718                                               QFixed *left, QFixed *right) const
  2723 {
  2719 {
  2724 //     qDebug() << "floatMargins y=" << y;
  2720 //     qDebug() << "floatMargins y=" << y;
  2725     *left = layoutStruct->x_left;
  2721     *left = layoutStruct->x_left;
  2726     *right = layoutStruct->x_right;
  2722     *right = layoutStruct->x_right;
  2738         }
  2734         }
  2739     }
  2735     }
  2740 //     qDebug() << "floatMargins: left="<<*left<<"right="<<*right<<"y="<<y;
  2736 //     qDebug() << "floatMargins: left="<<*left<<"right="<<*right<<"y="<<y;
  2741 }
  2737 }
  2742 
  2738 
  2743 QFixed QTextDocumentLayoutPrivate::findY(QFixed yFrom, const QLayoutStruct *layoutStruct, QFixed requiredWidth) const
  2739 QFixed QTextDocumentLayoutPrivate::findY(QFixed yFrom, const QTextLayoutStruct *layoutStruct, QFixed requiredWidth) const
  2744 {
  2740 {
  2745     QFixed right, left;
  2741     QFixed right, left;
  2746     requiredWidth = qMin(requiredWidth, layoutStruct->x_right - layoutStruct->x_left);
  2742     requiredWidth = qMin(requiredWidth, layoutStruct->x_right - layoutStruct->x_left);
  2747 
  2743 
  2748 //     qDebug() << "findY:" << yFrom;
  2744 //     qDebug() << "findY:" << yFrom;