File indexing completed on 2024-04-28 11:38:41

0001 /**
0002  * This file is part of the HTML widget for KDE.
0003  *
0004  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
0005  *           (C) 2003 Apple Computer, Inc.
0006  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
0007  *           (C) 2007-2009 Germain Garand (germain@ebooksfrance.org)
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  */
0024 
0025 #include "rendering/render_canvas.h"
0026 #include "rendering/render_layer.h"
0027 #include "rendering/render_replaced.h"
0028 #include "xml/dom_docimpl.h"
0029 
0030 #include "khtmlview.h"
0031 #include "khtml_part.h"
0032 #include "khtml_debug.h"
0033 #include <QScrollBar>
0034 
0035 using namespace khtml;
0036 
0037 //#define BOX_DEBUG
0038 //#define SPEED_DEBUG
0039 #ifdef SPEED_DEBUG
0040 #include <QTime>
0041 #endif
0042 
0043 RenderCanvas::RenderCanvas(DOM::NodeImpl *node, KHTMLView *view)
0044     : RenderBlock(node)
0045 {
0046     // init RenderObject attributes
0047     setInline(false);
0048     setIsAnonymous(false);
0049 
0050     m_view = view;
0051     // try to contrain the width to the views width
0052 
0053     m_minWidth = 0;
0054     m_height = 0;
0055 
0056     m_width = m_minWidth;
0057     m_maxWidth = m_minWidth;
0058 
0059     m_rootWidth = m_rootHeight = 0;
0060     m_viewportWidth = m_viewportHeight = 0;
0061     m_cachedDocWidth = m_cachedDocHeight = -1;
0062 
0063     setPositioned(true); // to 0,0 :)
0064 
0065     m_staticMode = false;
0066     m_pagedMode = false;
0067     m_printImages = true;
0068 
0069     m_pageTop = 0;
0070     m_pageBottom = 0;
0071 
0072     m_page = nullptr;
0073 
0074     m_maximalOutlineSize = 0;
0075 
0076     m_selectionStart = nullptr;
0077     m_selectionEnd = nullptr;
0078     m_selectionStartPos = -1;
0079     m_selectionEndPos = -1;
0080 
0081     m_needsWidgetMasks = false;
0082 
0083     m_isPerformingLayout = false;
0084 
0085     // Create a new root layer for our layer hierarchy.
0086     m_layer = new(node->document()->renderArena()) RenderLayer(this);
0087 }
0088 
0089 RenderCanvas::~RenderCanvas()
0090 {
0091     delete m_page;
0092 }
0093 
0094 void RenderCanvas::setStyle(RenderStyle *style)
0095 {
0096     /*
0097     if (m_pagedMode)
0098         style->setOverflow(OHIDDEN); */
0099     RenderBlock::setStyle(style);
0100 }
0101 
0102 void RenderCanvas::calcHeight()
0103 {
0104     if (m_pagedMode || !m_view) {
0105         m_height = m_rootHeight;
0106     } else {
0107         m_height = m_view->visibleHeight();
0108     }
0109 }
0110 
0111 void RenderCanvas::calcWidth()
0112 {
0113     // the width gets set by KHTMLView::print when printing to a printer.
0114     if (m_pagedMode || !m_view) {
0115         m_width = m_rootWidth;
0116         return;
0117     }
0118 
0119     m_width = m_view ? m_view->frameWidth() : m_minWidth;
0120 
0121     if (style()->marginLeft().isFixed()) {
0122         m_marginLeft = style()->marginLeft().value();
0123     } else {
0124         m_marginLeft = 0;
0125     }
0126 
0127     if (style()->marginRight().isFixed()) {
0128         m_marginRight = style()->marginRight().value();
0129     } else {
0130         m_marginRight = 0;
0131     }
0132 }
0133 
0134 void RenderCanvas::calcMinMaxWidth()
0135 {
0136     KHTMLAssert(!minMaxKnown());
0137 
0138     RenderBlock::calcMinMaxWidth();
0139 
0140     m_maxWidth = m_minWidth;
0141 
0142     setMinMaxKnown();
0143 }
0144 
0145 void RenderCanvas::layout()
0146 {
0147     m_isPerformingLayout = true;
0148 
0149     if (m_pagedMode) {
0150         m_minWidth = m_width;
0151 //        m_maxWidth = m_width;
0152     }
0153 
0154     m_needsFullRepaint =  markedForRepaint() || !view() || view()->needsFullRepaint() || m_pagedMode;
0155 
0156     setChildNeedsLayout(true);
0157     setMinMaxKnown(false);
0158     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
0159         c->setChildNeedsLayout(true);
0160     }
0161 
0162     int oldWidth = m_width;
0163     int oldHeight = m_height;
0164 
0165     m_cachedDocWidth = m_cachedDocHeight = -1;
0166 
0167     if (m_pagedMode || !m_view) {
0168         m_width = m_rootWidth;
0169         m_height = m_rootHeight;
0170     } else {
0171         m_viewportWidth = m_width = m_view->visibleWidth();
0172         m_viewportHeight = m_height = m_view->visibleHeight();
0173     }
0174 
0175 #ifdef SPEED_DEBUG
0176     QTime qt;
0177     qt.start();
0178 #endif
0179 
0180     if (recalcMinMax()) {
0181         recalcMinMaxWidths();
0182     }
0183 
0184 #ifdef SPEED_DEBUG
0185     qCDebug(KHTML_LOG) << "RenderCanvas::calcMinMax time used=" << qt.elapsed();
0186     qt.start();
0187 #endif
0188 
0189     bool relayoutChildren = (oldWidth != m_width) || (oldHeight != m_height);
0190 
0191     RenderBlock::layoutBlock(relayoutChildren);
0192 
0193 #ifdef SPEED_DEBUG
0194     qCDebug(KHTML_LOG) << "RenderCanvas::layout time used=" << qt.elapsed();
0195     qt.start();
0196 #endif
0197 
0198     updateDocumentSize();
0199 
0200     layer()->updateLayerPositions(layer(), needsFullRepaint(), true);
0201 
0202     if (!m_pagedMode && m_needsWidgetMasks) {
0203         layer()->updateWidgetMasks(layer());
0204     }
0205 
0206     scheduleDeferredRepaints();
0207     setNeedsLayout(false);
0208 
0209     m_isPerformingLayout = false;
0210 #ifdef SPEED_DEBUG
0211     qCDebug(KHTML_LOG) << "RenderCanvas::end time used=" << qt.elapsed();
0212 #endif
0213 }
0214 
0215 void RenderCanvas::setNeedsWidgetMasks(bool b)
0216 {
0217     if (b == m_needsWidgetMasks) {
0218         return;
0219     }
0220     m_needsWidgetMasks = b;
0221     KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_view);
0222     // ### should be reversible
0223     if (k && b && k->m_kwp->isRedirected()) {
0224         k->m_kwp->setIsRedirected(!b);
0225         if (k->m_kwp->renderWidget()) {
0226             k->m_kwp->renderWidget()->setNeedsLayout(true);
0227         }
0228     }
0229 }
0230 
0231 void RenderCanvas::updateDocumentSize()
0232 {
0233     // update our cached document size
0234     int hDocH = m_cachedDocHeight = docHeight();
0235     int hDocW = m_cachedDocWidth = docWidth();
0236 
0237     int zLevel = m_view ? m_view->zoomLevel() : 100;
0238     hDocW = hDocW * zLevel / 100;
0239     hDocH = hDocH * zLevel / 100;
0240 
0241     if (!m_pagedMode && m_view) {
0242 
0243         // we need to adjust the document's size to make sure we don't enter
0244         // an endless cycle of scrollbars being added, then removed at the next layout.
0245 
0246         bool vss = m_view->verticalScrollBar()->isVisible();
0247         bool hss = m_view->horizontalScrollBar()->isVisible();
0248 
0249         // calculate the extent of scrollbars
0250         int vsPixSize = m_view->verticalScrollBar()->sizeHint().width();
0251         int hsPixSize = m_view->horizontalScrollBar()->sizeHint().height();
0252 
0253         // this variable holds the size the viewport will have after the inner content is resized to
0254         // the new document dimensions
0255         QSize viewport = m_view->maximumViewportSize();
0256 
0257         // of course, if the scrollbar policy isn't auto, there's no point adjusting any value..
0258         int overrideH = m_view->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded ? 0 : hDocH;
0259         int overrideW = m_view->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded ? 0 : hDocW;
0260 
0261         if (!overrideW && hDocW > viewport.width()) {
0262             viewport.setHeight(viewport.height() - hsPixSize);
0263         }
0264         if (!overrideH && hDocH > viewport.height()) {
0265             viewport.setWidth(viewport.width() - vsPixSize);
0266         }
0267 
0268         // if we are about to show a scrollbar, and the document is sized to the viewport w or h,
0269         // then reserve the scrollbar space so that it doesn't trigger the _other_ scrollbar
0270 
0271         if (!vss && m_width - vsPixSize == viewport.width() &&
0272                 hDocW <= m_width) {
0273             hDocW = qMin(hDocW, viewport.width());
0274         }
0275 
0276         if (!hss && m_height - hsPixSize == viewport.height() &&
0277                 hDocH <= m_height) {
0278             hDocH = qMin(hDocH, viewport.height());
0279         }
0280 
0281         // likewise, if a scrollbar is shown, and we have a cunning plan to turn it off,
0282         // think again if we are falling downright in the hysteresis zone
0283 
0284         if (vss && viewport.width() > hDocW && hDocW > m_view->visibleWidth()) {
0285             hDocW = viewport.width() + 1;
0286         }
0287 
0288         if (hss && viewport.height() > hDocH && hDocH > m_view->visibleHeight()) {
0289             hDocH = viewport.height() + 1;
0290         }
0291 
0292         m_view->resizeContents((overrideW ? overrideW : hDocW), (overrideH ? overrideH : hDocH));
0293 
0294     }
0295     layer()->resize(qMax(m_cachedDocWidth, int(m_width)), qMax(m_cachedDocHeight, m_height));
0296 }
0297 
0298 void RenderCanvas::updateDocSizeAfterLayerTranslation(RenderObject *o, bool posXOffset, bool posYOffset)
0299 {
0300     if (needsLayout()) {
0301         return;
0302     }
0303     int rightmost, lowest;
0304     o->absolutePosition(rightmost, lowest);
0305     if (posXOffset) {
0306         rightmost += o->rightmostPosition(false, true);
0307         setCachedDocWidth(qMax(docWidth(), rightmost));
0308     } else {
0309         setCachedDocWidth(-1);
0310     }
0311     if (posYOffset) {
0312         lowest += o->lowestPosition(false, true);
0313         setCachedDocHeight(qMax(docHeight(), lowest));
0314     } else {
0315         setCachedDocHeight(-1);
0316     }
0317 //    qCDebug(KHTML_LOG) << " posXOffset: " << posXOffset << " posYOffset " << posYOffset << " m_cachedDocWidth  " <<  m_cachedDocWidth << " m_cachedDocHeight  " << m_cachedDocHeight;
0318     updateDocumentSize();
0319 }
0320 
0321 QRegion RenderCanvas::staticRegion() const
0322 {
0323     QRegion ret = QRegion();
0324 
0325     // position:fixed objects
0326     if (m_positionedObjects) {
0327         RenderObject *obj;
0328         QListIterator<RenderObject *> it(*m_positionedObjects);
0329         while (it.hasNext()) {
0330             obj = it.next();
0331             if (obj->style()->position() == PFIXED && obj->layer()) {
0332                 ret += obj->layer()->paintedRegion(layer());
0333                 assert(m_fixedPosition.contains(obj));
0334             }
0335         }
0336     }
0337 
0338     // background-attachment:fixed images
0339     QSetIterator<RenderObject *> i(m_fixedBackground);
0340     while (i.hasNext()) {
0341         RenderObject *ro = i.next();
0342         if (ro && ro->isBox()) {
0343             int d1, d2, d3, d4;
0344             const BackgroundLayer *bgLayer = ro->style()->backgroundLayers();
0345             while (bgLayer) {
0346                 CachedImage *bg = bgLayer->backgroundAttachment() == BGAFIXED ? bgLayer->backgroundImage() : nullptr;
0347                 if (bg && bg->isComplete() && !bg->isTransparent() && !bg->isErrorImage()) {
0348                     int xpos, ypos;
0349                     absolutePosition(xpos, ypos);
0350                     ret += static_cast<RenderBox *>(ro)->getFixedBackgroundImageRect(bgLayer, d1, d2, d3, d4)
0351                            .intersected(QRect(xpos, ypos, ro->width(), ro->height()));
0352                 }
0353                 bgLayer = bgLayer->next();
0354             }
0355         }
0356     }
0357     return ret;
0358 }
0359 
0360 bool RenderCanvas::needsFullRepaint() const
0361 {
0362     return m_needsFullRepaint || m_pagedMode;
0363 }
0364 
0365 void RenderCanvas::repaintViewRectangle(int x, int y, int w, int h, bool asap)
0366 {
0367     KHTMLAssert(view());
0368     view()->scheduleRepaint(x, y, w, h, asap);
0369 }
0370 
0371 bool RenderCanvas::absolutePosition(int &xPos, int &yPos, bool f) const
0372 {
0373     if (f && m_pagedMode) {
0374         xPos = 0;
0375         yPos = m_pageTop;
0376     } else if (f && m_view) {
0377         xPos = m_view->contentsX();
0378         yPos = m_view->contentsY();
0379     } else {
0380         xPos = yPos = 0;
0381     }
0382     return true;
0383 }
0384 
0385 void RenderCanvas::paint(PaintInfo &paintInfo, int _tx, int _ty)
0386 {
0387 #ifdef DEBUG_LAYOUT
0388     qCDebug(KHTML_LOG) << renderName() << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")";
0389 #endif
0390 
0391     // 1. paint background, borders etc
0392     if (paintInfo.phase == PaintActionElementBackground) {
0393         paintBoxDecorations(paintInfo, _tx, _ty);
0394         return;
0395     }
0396 
0397     // 2. paint contents
0398     for (RenderObject *child = firstChild(); child; child = child->nextSibling())
0399         if (!child->layer() && !child->isFloating()) {
0400             child->paint(paintInfo, _tx, _ty);
0401         }
0402 
0403     // 3. paint floats.
0404     if (paintInfo.phase == PaintActionFloat) {
0405         paintFloats(paintInfo, _tx, _ty);
0406     }
0407 
0408 #ifdef BOX_DEBUG
0409     if (m_view) {
0410         _tx += m_view->contentsX();
0411         _ty += m_view->contentsY();
0412     }
0413 
0414     outlineBox(paintInfo.p, _tx, _ty);
0415 #endif
0416 
0417 }
0418 
0419 void RenderCanvas::paintBoxDecorations(PaintInfo &paintInfo, int /*_tx*/, int /*_ty*/)
0420 {
0421     if ((firstChild() && firstChild()->style()->visibility() == VISIBLE) || !view()) {
0422         return;
0423     }
0424 
0425     paintInfo.p->fillRect(paintInfo.r, view()->palette().color(QPalette::Active, QPalette::Base));
0426 }
0427 
0428 void RenderCanvas::repaintRectangle(int x, int y, int w, int h, Priority p, bool f)
0429 {
0430     if (m_staticMode) {
0431         return;
0432     }
0433 //    qCDebug(KHTML_LOG) << "updating views contents (" << x << "/" << y << ") (" << w << "/" << h << ")";
0434 
0435     if (f && m_pagedMode) {
0436         y += m_pageTop;
0437     } else if (f && m_view) {
0438         x += m_view->contentsX();
0439         y += m_view->contentsY();
0440     }
0441 
0442     QRect vr = viewRect();
0443     QRect ur(x, y, w, h);
0444 
0445     if (m_view && ur.intersects(vr)) {
0446 
0447         if (p == RealtimePriority) {
0448             m_view->updateContents(ur);
0449         } else if (p == HighPriority) {
0450             m_view->scheduleRepaint(x, y, w, h, true /*asap*/);
0451         } else {
0452             m_view->scheduleRepaint(x, y, w, h);
0453         }
0454     }
0455 }
0456 
0457 void RenderCanvas::deferredRepaint(RenderObject *o)
0458 {
0459     m_dirtyChildren.append(o);
0460 }
0461 
0462 void RenderCanvas::scheduleDeferredRepaints()
0463 {
0464     if (!needsFullRepaint()) {
0465         QList<RenderObject *>::const_iterator it;
0466         for (it = m_dirtyChildren.constBegin(); it != m_dirtyChildren.constEnd(); ++it) {
0467             (*it)->repaint();
0468         }
0469     }
0470     //qCDebug(KHTML_LOG) << "scheduled deferred repaints: " << m_dirtyChildren.count() << " needed full repaint: " << needsFullRepaint();
0471     m_dirtyChildren.clear();
0472 }
0473 
0474 void RenderCanvas::repaint(Priority p)
0475 {
0476     if (m_view && !m_staticMode) {
0477         if (p == RealtimePriority) {
0478             //m_view->resizeContents(docWidth(), docHeight());
0479             m_view->unscheduleRepaint();
0480             if (needsLayout()) {
0481                 m_view->scheduleRelayout();
0482                 return;
0483             }
0484             // ### same as in repaintRectangle
0485             m_view->updateContents(m_view->contentsX(), m_view->contentsY(),
0486                                    m_view->visibleWidth(), m_view->visibleHeight());
0487         } else if (p == HighPriority)
0488             m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(),
0489                                     m_view->visibleWidth(), m_view->visibleHeight(), true /*asap*/);
0490         else
0491             m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(),
0492                                     m_view->visibleWidth(), m_view->visibleHeight());
0493     }
0494 }
0495 
0496 static QRect enclosingPositionedRect(RenderObject *n)
0497 {
0498     RenderObject *enclosingParent =  n->containingBlock();
0499     QRect rect(0, 0, 0, 0);
0500     if (enclosingParent) {
0501         int ox, oy;
0502         enclosingParent->absolutePosition(ox, oy);
0503         if (!enclosingParent->hasOverflowClip()) {
0504             ox += enclosingParent->overflowLeft();
0505             oy += enclosingParent->overflowTop();
0506         }
0507         rect.setX(ox);
0508         rect.setY(oy);
0509         rect.setWidth(enclosingParent->effectiveWidth());
0510         rect.setHeight(enclosingParent->effectiveHeight());
0511     }
0512     return rect;
0513 }
0514 
0515 void RenderCanvas::addStaticObject(RenderObject *o, bool pos)
0516 {
0517     QSet<RenderObject *> &set = pos ? m_fixedPosition : m_fixedBackground;
0518     if (!o || !o->isBox() || set.contains(o)) {
0519         return;
0520     }
0521     set.insert(o);
0522     if (view()) {
0523         view()->addStaticObject(pos);
0524     }
0525 }
0526 
0527 void RenderCanvas::removeStaticObject(RenderObject *o, bool pos)
0528 {
0529     QSet<RenderObject *> &set = pos ? m_fixedPosition : m_fixedBackground;
0530     if (!o || !o->isBox() || !set.contains(o)) {
0531         return;
0532     }
0533     set.remove(o);
0534     if (view()) {
0535         view()->removeStaticObject(pos);
0536     }
0537 }
0538 
0539 QRect RenderCanvas::selectionRect() const
0540 {
0541     RenderObject *r = m_selectionStart;
0542     if (!r) {
0543         return QRect();
0544     }
0545 
0546     QRect selectionRect = enclosingPositionedRect(r);
0547 
0548     while (r && r != m_selectionEnd) {
0549         RenderObject *n;
0550         if (!(n = r->firstChild())) {
0551             if (!(n = r->nextSibling())) {
0552                 n = r->parent();
0553                 while (n && !n->nextSibling()) {
0554                     n = n->parent();
0555                 }
0556                 if (n) {
0557                     n = n->nextSibling();
0558                 }
0559             }
0560         }
0561         r = n;
0562         if (r) {
0563             selectionRect = selectionRect.united(enclosingPositionedRect(r));
0564         }
0565     }
0566 
0567     return selectionRect;
0568 }
0569 
0570 void RenderCanvas::setSelection(RenderObject *s, int sp, RenderObject *e, int ep)
0571 {
0572     // Check we got valid renderobjects. www.msnbc.com and clicking
0573     // around, to find the case where this happened.
0574     if (!s || !e) {
0575         qCWarning(KHTML_LOG) << "RenderCanvas::setSelection() called with start=" << s << " end=" << e;
0576         return;
0577     }
0578 //     qCDebug(KHTML_LOG) << "RenderCanvas::setSelection(" << s << "," << sp << "," << e << "," << ep << ")";
0579 
0580     bool changedSelectionBorder = (s != m_selectionStart || e != m_selectionEnd);
0581 
0582     // Cut out early if the selection hasn't changed.
0583     if (!changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos == ep) {
0584         return;
0585     }
0586 
0587     // Record the old selected objects.  Will be used later
0588     // to delta against the selected objects.
0589 
0590     RenderObject *oldStart = m_selectionStart;
0591     int oldStartPos = m_selectionStartPos;
0592     RenderObject *oldEnd = m_selectionEnd;
0593     int oldEndPos = m_selectionEndPos;
0594     QList<RenderObject *> oldSelectedInside;
0595     QList<RenderObject *> newSelectedInside;
0596     RenderObject *os = oldStart;
0597 
0598     while (os && os != oldEnd) {
0599         RenderObject *no;
0600         if (!(no = os->firstChild())) {
0601             if (!(no = os->nextSibling())) {
0602                 no = os->parent();
0603                 while (no && !no->nextSibling()) {
0604                     no = no->parent();
0605                 }
0606                 if (no) {
0607                     no = no->nextSibling();
0608                 }
0609             }
0610         }
0611         if (os->selectionState() == SelectionInside && !oldSelectedInside.contains(os)) {
0612             oldSelectedInside.append(os);
0613         }
0614 
0615         os = no;
0616     }
0617     if (changedSelectionBorder) {
0618         clearSelection(false);
0619     }
0620 
0621     while (s->firstChild()) {
0622         s = s->firstChild();
0623     }
0624     while (e->lastChild()) {
0625         e = e->lastChild();
0626     }
0627 
0628 #if 0
0629     bool changedSelectionBorder = (s != m_selectionStart || e != m_selectionEnd);
0630 
0631     if (!changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos = ep) {
0632         return;
0633     }
0634 #endif
0635 
0636     // set selection start
0637     if (m_selectionStart) {
0638         m_selectionStart->setIsSelectionBorder(false);
0639     }
0640     m_selectionStart = s;
0641     if (m_selectionStart) {
0642         m_selectionStart->setIsSelectionBorder(true);
0643     }
0644     m_selectionStartPos = sp;
0645 
0646     // set selection end
0647     if (m_selectionEnd) {
0648         m_selectionEnd->setIsSelectionBorder(false);
0649     }
0650     m_selectionEnd = e;
0651     if (m_selectionEnd) {
0652         m_selectionEnd->setIsSelectionBorder(true);
0653     }
0654     m_selectionEndPos = ep;
0655 
0656 #if 0
0657     // qCDebug(KHTML_LOG) << "old selection (" << oldStart << "," << oldStartPos << "," << oldEnd << "," << oldEndPos << ")";
0658     // qCDebug(KHTML_LOG) << "new selection (" << s << "," << sp << "," << e << "," << ep << ")";
0659 #endif
0660 
0661     // update selection status of all objects between m_selectionStart and m_selectionEnd
0662     RenderObject *o = s;
0663 
0664     while (o && o != e) {
0665         o->setSelectionState(SelectionInside);
0666 //      qCDebug(KHTML_LOG) << "setting selected " << o << ", " << o->isText();
0667         RenderObject *no;
0668         if (!(no = o->firstChild()))
0669             if (!(no = o->nextSibling())) {
0670                 no = o->parent();
0671                 while (no && !no->nextSibling()) {
0672                     no = no->parent();
0673                 }
0674                 if (no) {
0675                     no = no->nextSibling();
0676                 }
0677             }
0678         if (o->selectionState() == SelectionInside && !newSelectedInside.contains(o)) {
0679             newSelectedInside.append(o);
0680         }
0681 
0682         o = no;
0683     }
0684     s->setSelectionState(SelectionStart);
0685     e->setSelectionState(SelectionEnd);
0686     if (s == e) {
0687         s->setSelectionState(SelectionBoth);
0688     }
0689 
0690     if (!m_view) {
0691         return;
0692     }
0693 
0694     int i;
0695     i = newSelectedInside.indexOf(s);
0696     if (i != -1) {
0697         newSelectedInside.removeAt(i);
0698     }
0699     i = newSelectedInside.indexOf(e);
0700     if (i != -1) {
0701         newSelectedInside.removeAt(i);
0702     }
0703 
0704     QRect updateRect;
0705 
0706     // Don't use repaint() because it will cause all rects to
0707     // be united (see khtmlview::scheduleRepaint()).  Instead
0708     // just draw damage rects for objects that have a change
0709     // in selection state.
0710     // ### for Qt, updateContents will unite them, too. This has to be
0711     // circumvented somehow (LS)
0712 
0713     // Are any of the old fully selected objects not in the new selection?
0714     // If so we have to draw them.
0715     // Could be faster by building list of non-intersecting rectangles rather
0716     // than unioning rectangles.
0717     QListIterator<RenderObject *> oldIterator(oldSelectedInside);
0718     bool firstRect = true;
0719     while (oldIterator.hasNext()) {
0720         o = oldIterator.next();
0721         if (!newSelectedInside.contains(o)) {
0722             if (firstRect) {
0723                 updateRect = enclosingPositionedRect(o);
0724                 firstRect = false;
0725             } else {
0726                 updateRect = updateRect.united(enclosingPositionedRect(o));
0727             }
0728         }
0729     }
0730     if (!firstRect) {
0731         m_view->updateContents(updateRect);
0732     }
0733 
0734     // Are any of the new fully selected objects not in the previous selection?
0735     // If so we have to draw them.
0736     // Could be faster by building list of non-intersecting rectangles rather
0737     // than unioning rectangles.
0738     QListIterator<RenderObject *> newIterator(newSelectedInside);
0739     firstRect = true;
0740     while (newIterator.hasNext()) {
0741         o = newIterator.next();
0742         if (!oldSelectedInside.contains(o)) {
0743             if (firstRect) {
0744                 updateRect = enclosingPositionedRect(o);
0745                 firstRect = false;
0746             } else {
0747                 updateRect = updateRect.united(enclosingPositionedRect(o));
0748             }
0749         }
0750     }
0751     if (!firstRect) {
0752         m_view->updateContents(updateRect);
0753     }
0754 
0755     // Is the new starting object different, or did the position in the starting
0756     // element change?  If so we have to draw it.
0757     if (oldStart != m_selectionStart ||
0758             (oldStart == oldEnd && (oldStartPos != m_selectionStartPos || oldEndPos != m_selectionEndPos)) ||
0759             (oldStart == m_selectionStart && oldStartPos != m_selectionStartPos)) {
0760         m_view->updateContents(enclosingPositionedRect(m_selectionStart));
0761     }
0762 
0763     // Draw the old selection start object if it's different than the new selection
0764     // start object.
0765     if (oldStart && oldStart != m_selectionStart) {
0766         m_view->updateContents(enclosingPositionedRect(oldStart));
0767     }
0768 
0769     // Does the selection span objects and is the new end object different, or did the position
0770     // in the end element change?  If so we have to draw it.
0771     if (/*(oldStart != oldEnd || !oldEnd) &&*/
0772         (oldEnd != m_selectionEnd ||
0773          (oldEnd == m_selectionEnd && oldEndPos != m_selectionEndPos))) {
0774         m_view->updateContents(enclosingPositionedRect(m_selectionEnd));
0775     }
0776 
0777     // Draw the old selection end object if it's different than the new selection
0778     // end object.
0779     if (oldEnd && oldEnd != m_selectionEnd) {
0780         m_view->updateContents(enclosingPositionedRect(oldEnd));
0781     }
0782 }
0783 
0784 void RenderCanvas::clearSelection(bool doRepaint)
0785 {
0786     // update selection status of all objects between m_selectionStart and m_selectionEnd
0787     RenderObject *o = m_selectionStart;
0788     while (o && o != m_selectionEnd) {
0789         if (o->selectionState() != SelectionNone)
0790             if (doRepaint) {
0791                 o->repaint();
0792             }
0793         o->setSelectionState(SelectionNone);
0794         o->repaint();
0795         RenderObject *no;
0796         if (!(no = o->firstChild()))
0797             if (!(no = o->nextSibling())) {
0798                 no = o->parent();
0799                 while (no && !no->nextSibling()) {
0800                     no = no->parent();
0801                 }
0802                 if (no) {
0803                     no = no->nextSibling();
0804                 }
0805             }
0806         o = no;
0807     }
0808     if (m_selectionEnd) {
0809         m_selectionEnd->setSelectionState(SelectionNone);
0810         if (doRepaint) {
0811             m_selectionEnd->repaint();
0812         }
0813     }
0814 
0815     // set selection start & end to 0
0816     if (m_selectionStart) {
0817         m_selectionStart->setIsSelectionBorder(false);
0818     }
0819     m_selectionStart = nullptr;
0820     m_selectionStartPos = -1;
0821 
0822     if (m_selectionEnd) {
0823         m_selectionEnd->setIsSelectionBorder(false);
0824     }
0825     m_selectionEnd = nullptr;
0826     m_selectionEndPos = -1;
0827 }
0828 
0829 void RenderCanvas::selectionStartEnd(int &spos, int &epos)
0830 {
0831     spos = m_selectionStartPos;
0832     epos = m_selectionEndPos;
0833 }
0834 
0835 QRect RenderCanvas::viewRect() const
0836 {
0837     if (m_pagedMode)
0838         if (m_pageTop == m_pageBottom) {
0839             // qCDebug(KHTML_LOG) << "viewRect: " << QRect(0, m_pageTop, m_width, m_height);
0840             return QRect(0, m_pageTop, m_width, m_height);
0841         } else {
0842             // qCDebug(KHTML_LOG) << "viewRect: " << QRect(0, m_pageTop, m_width, m_pageBottom - m_pageTop);
0843             return QRect(0, m_pageTop, m_width, m_pageBottom - m_pageTop);
0844         }
0845     else if (m_view) {
0846         const int z = m_view->zoomLevel() ? m_view->zoomLevel() : 100;
0847         return QRect(m_view->contentsX() * 100 / z, m_view->contentsY() * 100 / z,
0848                      m_view->visibleWidth(), m_view->visibleHeight());
0849     } else {
0850         return QRect(0, 0, m_rootWidth, m_rootHeight);
0851     }
0852 }
0853 
0854 int RenderCanvas::docHeight() const
0855 {
0856     if (m_cachedDocHeight != -1) {
0857         return m_cachedDocHeight;
0858     }
0859 
0860     int h;
0861     if (m_pagedMode || !m_view) {
0862         h = m_height;
0863     } else {
0864         h = 0;
0865     }
0866 
0867     RenderObject *fc = firstChild();
0868     if (fc) {
0869         int dh = fc->overflowHeight() + fc->marginTop() + fc->marginBottom();
0870         int lowestPos = fc->lowestPosition(false);
0871 // qCDebug(KHTML_LOG) << "h " << h << " lowestPos " << lowestPos << " dh " << dh << " fc->rh " << fc->effectiveHeight() << " fc->height() " << fc->height();
0872         if (lowestPos > dh) {
0873             dh = lowestPos;
0874         }
0875         lowestPos = lowestAbsolutePosition();
0876         if (lowestPos > dh) {
0877             dh = lowestPos;
0878         }
0879         if (dh > h) {
0880             h = dh;
0881         }
0882     }
0883 
0884     RenderLayer *layer = m_layer;
0885     h = qMax(h, layer->yPos() + layer->height());
0886 // qCDebug(KHTML_LOG) << "h " << h << " layer(" << layer->renderer()->renderName() << "@" << layer->renderer() << ")->height " << layer->height() << " lp " << (layer->yPos() + layer->height()) << " height() " << layer->renderer()->height() << " rh " << layer->renderer()->effectiveHeight();
0887     return h;
0888 }
0889 
0890 int RenderCanvas::docWidth() const
0891 {
0892     if (m_cachedDocWidth != -1) {
0893         return m_cachedDocWidth;
0894     }
0895 
0896     int w;
0897     if (m_pagedMode || !m_view) {
0898         w = m_width;
0899     } else {
0900         w = 0;
0901     }
0902 
0903     RenderObject *fc = firstChild();
0904     if (fc) {
0905         // ow: like effectiveWidth() but without the negative
0906         const int ow = fc->hasOverflowClip() ? fc->width() : fc->overflowWidth();
0907         int dw = ow + fc->marginLeft() + fc->marginRight();
0908         int rightmostPos = fc->rightmostPosition(false);
0909 // qCDebug(KHTML_LOG) << "w " << w << " rightmostPos " << rightmostPos << " dw " << dw << " fc->rw " << fc->effectiveWidth() << " fc->width() " << fc->width();
0910         if (rightmostPos > dw) {
0911             dw = rightmostPos;
0912         }
0913         rightmostPos = rightmostAbsolutePosition();
0914         if (rightmostPos > dw) {
0915             dw = rightmostPos;
0916         }
0917         if (dw > w) {
0918             w = dw;
0919         }
0920     }
0921 
0922     RenderLayer *layer = m_layer;
0923     w = qMax(w, layer->xPos() + layer->width());
0924 // qCDebug(KHTML_LOG) << "w " << w << " layer(" << layer->renderer()->renderName() << ")->width " << layer->width() << " rm " << (layer->xPos() + layer->width()) << " width() " << layer->renderer()->width() << " rw " << layer->renderer()->effectiveWidth();
0925     return w;
0926 }
0927 
0928 RenderPage *RenderCanvas::page()
0929 {
0930     if (!m_page) {
0931         m_page = new RenderPage(this);
0932     }
0933     return m_page;
0934 }
0935 
0936 void RenderCanvas::updateInvalidatedFonts()
0937 {
0938     for (RenderObject *o = firstChild(); o; o = o->nextRenderer()) {
0939         if (o->style()->htmlFont().isInvalidated()) {
0940             o->setNeedsLayoutAndMinMaxRecalc();
0941 //          qCDebug(KHTML_LOG) << "updating object using invalid font" << o->style()->htmlFont().getFontDef().family << o->information();
0942         }
0943     }
0944 }