File indexing completed on 2024-04-28 15:23:58
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 }