KHtml

render_canvas.cpp
1 /**
2  * This file is part of the HTML widget for KDE.
3  *
4  * Copyright (C) 1999-2003 Lars Knoll ([email protected])
5  * (C) 2003 Apple Computer, Inc.
6  * (C) 2005 Allan Sandfeld Jensen ([email protected])
7  * (C) 2007-2009 Germain Garand ([email protected])
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #include "rendering/render_canvas.h"
26 #include "rendering/render_layer.h"
27 #include "rendering/render_replaced.h"
28 #include "xml/dom_docimpl.h"
29 
30 #include "khtmlview.h"
31 #include "khtml_part.h"
32 #include "khtml_debug.h"
33 #include <QScrollBar>
34 
35 using namespace khtml;
36 
37 //#define BOX_DEBUG
38 //#define SPEED_DEBUG
39 #ifdef SPEED_DEBUG
40 #include <QTime>
41 #endif
42 
43 RenderCanvas::RenderCanvas(DOM::NodeImpl *node, KHTMLView *view)
44  : RenderBlock(node)
45 {
46  // init RenderObject attributes
47  setInline(false);
48  setIsAnonymous(false);
49 
50  m_view = view;
51  // try to contrain the width to the views width
52 
53  m_minWidth = 0;
54  m_height = 0;
55 
56  m_width = m_minWidth;
57  m_maxWidth = m_minWidth;
58 
59  m_rootWidth = m_rootHeight = 0;
60  m_viewportWidth = m_viewportHeight = 0;
61  m_cachedDocWidth = m_cachedDocHeight = -1;
62 
63  setPositioned(true); // to 0,0 :)
64 
65  m_staticMode = false;
66  m_pagedMode = false;
67  m_printImages = true;
68 
69  m_pageTop = 0;
70  m_pageBottom = 0;
71 
72  m_page = nullptr;
73 
74  m_maximalOutlineSize = 0;
75 
76  m_selectionStart = nullptr;
77  m_selectionEnd = nullptr;
78  m_selectionStartPos = -1;
79  m_selectionEndPos = -1;
80 
81  m_needsWidgetMasks = false;
82 
83  m_isPerformingLayout = false;
84 
85  // Create a new root layer for our layer hierarchy.
86  m_layer = new(node->document()->renderArena()) RenderLayer(this);
87 }
88 
89 RenderCanvas::~RenderCanvas()
90 {
91  delete m_page;
92 }
93 
94 void RenderCanvas::setStyle(RenderStyle *style)
95 {
96  /*
97  if (m_pagedMode)
98  style->setOverflow(OHIDDEN); */
99  RenderBlock::setStyle(style);
100 }
101 
102 void RenderCanvas::calcHeight()
103 {
104  if (m_pagedMode || !m_view) {
105  m_height = m_rootHeight;
106  } else {
107  m_height = m_view->visibleHeight();
108  }
109 }
110 
111 void RenderCanvas::calcWidth()
112 {
113  // the width gets set by KHTMLView::print when printing to a printer.
114  if (m_pagedMode || !m_view) {
115  m_width = m_rootWidth;
116  return;
117  }
118 
119  m_width = m_view ? m_view->frameWidth() : m_minWidth;
120 
121  if (style()->marginLeft().isFixed()) {
122  m_marginLeft = style()->marginLeft().value();
123  } else {
124  m_marginLeft = 0;
125  }
126 
127  if (style()->marginRight().isFixed()) {
128  m_marginRight = style()->marginRight().value();
129  } else {
130  m_marginRight = 0;
131  }
132 }
133 
134 void RenderCanvas::calcMinMaxWidth()
135 {
136  KHTMLAssert(!minMaxKnown());
137 
138  RenderBlock::calcMinMaxWidth();
139 
140  m_maxWidth = m_minWidth;
141 
142  setMinMaxKnown();
143 }
144 
145 void RenderCanvas::layout()
146 {
147  m_isPerformingLayout = true;
148 
149  if (m_pagedMode) {
150  m_minWidth = m_width;
151 // m_maxWidth = m_width;
152  }
153 
154  m_needsFullRepaint = markedForRepaint() || !view() || view()->needsFullRepaint() || m_pagedMode;
155 
156  setChildNeedsLayout(true);
157  setMinMaxKnown(false);
158  for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
159  c->setChildNeedsLayout(true);
160  }
161 
162  int oldWidth = m_width;
163  int oldHeight = m_height;
164 
165  m_cachedDocWidth = m_cachedDocHeight = -1;
166 
167  if (m_pagedMode || !m_view) {
168  m_width = m_rootWidth;
169  m_height = m_rootHeight;
170  } else {
171  m_viewportWidth = m_width = m_view->visibleWidth();
172  m_viewportHeight = m_height = m_view->visibleHeight();
173  }
174 
175 #ifdef SPEED_DEBUG
176  QTime qt;
177  qt.start();
178 #endif
179 
180  if (recalcMinMax()) {
181  recalcMinMaxWidths();
182  }
183 
184 #ifdef SPEED_DEBUG
185  qCDebug(KHTML_LOG) << "RenderCanvas::calcMinMax time used=" << qt.elapsed();
186  qt.start();
187 #endif
188 
189  bool relayoutChildren = (oldWidth != m_width) || (oldHeight != m_height);
190 
191  RenderBlock::layoutBlock(relayoutChildren);
192 
193 #ifdef SPEED_DEBUG
194  qCDebug(KHTML_LOG) << "RenderCanvas::layout time used=" << qt.elapsed();
195  qt.start();
196 #endif
197 
198  updateDocumentSize();
199 
200  layer()->updateLayerPositions(layer(), needsFullRepaint(), true);
201 
202  if (!m_pagedMode && m_needsWidgetMasks) {
203  layer()->updateWidgetMasks(layer());
204  }
205 
206  scheduleDeferredRepaints();
207  setNeedsLayout(false);
208 
209  m_isPerformingLayout = false;
210 #ifdef SPEED_DEBUG
211  qCDebug(KHTML_LOG) << "RenderCanvas::end time used=" << qt.elapsed();
212 #endif
213 }
214 
215 void RenderCanvas::setNeedsWidgetMasks(bool b)
216 {
217  if (b == m_needsWidgetMasks) {
218  return;
219  }
220  m_needsWidgetMasks = b;
221  KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_view);
222  // ### should be reversible
223  if (k && b && k->m_kwp->isRedirected()) {
224  k->m_kwp->setIsRedirected(!b);
225  if (k->m_kwp->renderWidget()) {
226  k->m_kwp->renderWidget()->setNeedsLayout(true);
227  }
228  }
229 }
230 
231 void RenderCanvas::updateDocumentSize()
232 {
233  // update our cached document size
234  int hDocH = m_cachedDocHeight = docHeight();
235  int hDocW = m_cachedDocWidth = docWidth();
236 
237  int zLevel = m_view ? m_view->zoomLevel() : 100;
238  hDocW = hDocW * zLevel / 100;
239  hDocH = hDocH * zLevel / 100;
240 
241  if (!m_pagedMode && m_view) {
242 
243  // we need to adjust the document's size to make sure we don't enter
244  // an endless cycle of scrollbars being added, then removed at the next layout.
245 
246  bool vss = m_view->verticalScrollBar()->isVisible();
247  bool hss = m_view->horizontalScrollBar()->isVisible();
248 
249  // calculate the extent of scrollbars
250  int vsPixSize = m_view->verticalScrollBar()->sizeHint().width();
251  int hsPixSize = m_view->horizontalScrollBar()->sizeHint().height();
252 
253  // this variable holds the size the viewport will have after the inner content is resized to
254  // the new document dimensions
255  QSize viewport = m_view->maximumViewportSize();
256 
257  // of course, if the scrollbar policy isn't auto, there's no point adjusting any value..
258  int overrideH = m_view->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded ? 0 : hDocH;
259  int overrideW = m_view->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded ? 0 : hDocW;
260 
261  if (!overrideW && hDocW > viewport.width()) {
262  viewport.setHeight(viewport.height() - hsPixSize);
263  }
264  if (!overrideH && hDocH > viewport.height()) {
265  viewport.setWidth(viewport.width() - vsPixSize);
266  }
267 
268  // if we are about to show a scrollbar, and the document is sized to the viewport w or h,
269  // then reserve the scrollbar space so that it doesn't trigger the _other_ scrollbar
270 
271  if (!vss && m_width - vsPixSize == viewport.width() &&
272  hDocW <= m_width) {
273  hDocW = qMin(hDocW, viewport.width());
274  }
275 
276  if (!hss && m_height - hsPixSize == viewport.height() &&
277  hDocH <= m_height) {
278  hDocH = qMin(hDocH, viewport.height());
279  }
280 
281  // likewise, if a scrollbar is shown, and we have a cunning plan to turn it off,
282  // think again if we are falling downright in the hysteresis zone
283 
284  if (vss && viewport.width() > hDocW && hDocW > m_view->visibleWidth()) {
285  hDocW = viewport.width() + 1;
286  }
287 
288  if (hss && viewport.height() > hDocH && hDocH > m_view->visibleHeight()) {
289  hDocH = viewport.height() + 1;
290  }
291 
292  m_view->resizeContents((overrideW ? overrideW : hDocW), (overrideH ? overrideH : hDocH));
293 
294  }
295  layer()->resize(qMax(m_cachedDocWidth, int(m_width)), qMax(m_cachedDocHeight, m_height));
296 }
297 
298 void RenderCanvas::updateDocSizeAfterLayerTranslation(RenderObject *o, bool posXOffset, bool posYOffset)
299 {
300  if (needsLayout()) {
301  return;
302  }
303  int rightmost, lowest;
304  o->absolutePosition(rightmost, lowest);
305  if (posXOffset) {
306  rightmost += o->rightmostPosition(false, true);
307  setCachedDocWidth(qMax(docWidth(), rightmost));
308  } else {
309  setCachedDocWidth(-1);
310  }
311  if (posYOffset) {
312  lowest += o->lowestPosition(false, true);
313  setCachedDocHeight(qMax(docHeight(), lowest));
314  } else {
315  setCachedDocHeight(-1);
316  }
317 // qCDebug(KHTML_LOG) << " posXOffset: " << posXOffset << " posYOffset " << posYOffset << " m_cachedDocWidth " << m_cachedDocWidth << " m_cachedDocHeight " << m_cachedDocHeight;
318  updateDocumentSize();
319 }
320 
321 QRegion RenderCanvas::staticRegion() const
322 {
323  QRegion ret = QRegion();
324 
325  // position:fixed objects
326  if (m_positionedObjects) {
327  RenderObject *obj;
328  QListIterator<RenderObject *> it(*m_positionedObjects);
329  while (it.hasNext()) {
330  obj = it.next();
331  if (obj->style()->position() == PFIXED && obj->layer()) {
332  ret += obj->layer()->paintedRegion(layer());
333  assert(m_fixedPosition.contains(obj));
334  }
335  }
336  }
337 
338  // background-attachment:fixed images
339  QSetIterator<RenderObject *> i(m_fixedBackground);
340  while (i.hasNext()) {
341  RenderObject *ro = i.next();
342  if (ro && ro->isBox()) {
343  int d1, d2, d3, d4;
344  const BackgroundLayer *bgLayer = ro->style()->backgroundLayers();
345  while (bgLayer) {
346  CachedImage *bg = bgLayer->backgroundAttachment() == BGAFIXED ? bgLayer->backgroundImage() : nullptr;
347  if (bg && bg->isComplete() && !bg->isTransparent() && !bg->isErrorImage()) {
348  int xpos, ypos;
349  absolutePosition(xpos, ypos);
350  ret += static_cast<RenderBox *>(ro)->getFixedBackgroundImageRect(bgLayer, d1, d2, d3, d4)
351  .intersected(QRect(xpos, ypos, ro->width(), ro->height()));
352  }
353  bgLayer = bgLayer->next();
354  }
355  }
356  }
357  return ret;
358 }
359 
360 bool RenderCanvas::needsFullRepaint() const
361 {
362  return m_needsFullRepaint || m_pagedMode;
363 }
364 
365 void RenderCanvas::repaintViewRectangle(int x, int y, int w, int h, bool asap)
366 {
367  KHTMLAssert(view());
368  view()->scheduleRepaint(x, y, w, h, asap);
369 }
370 
371 bool RenderCanvas::absolutePosition(int &xPos, int &yPos, bool f) const
372 {
373  if (f && m_pagedMode) {
374  xPos = 0;
375  yPos = m_pageTop;
376  } else if (f && m_view) {
377  xPos = m_view->contentsX();
378  yPos = m_view->contentsY();
379  } else {
380  xPos = yPos = 0;
381  }
382  return true;
383 }
384 
385 void RenderCanvas::paint(PaintInfo &paintInfo, int _tx, int _ty)
386 {
387 #ifdef DEBUG_LAYOUT
388  qCDebug(KHTML_LOG) << renderName() << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")";
389 #endif
390 
391  // 1. paint background, borders etc
392  if (paintInfo.phase == PaintActionElementBackground) {
393  paintBoxDecorations(paintInfo, _tx, _ty);
394  return;
395  }
396 
397  // 2. paint contents
398  for (RenderObject *child = firstChild(); child; child = child->nextSibling())
399  if (!child->layer() && !child->isFloating()) {
400  child->paint(paintInfo, _tx, _ty);
401  }
402 
403  // 3. paint floats.
404  if (paintInfo.phase == PaintActionFloat) {
405  paintFloats(paintInfo, _tx, _ty);
406  }
407 
408 #ifdef BOX_DEBUG
409  if (m_view) {
410  _tx += m_view->contentsX();
411  _ty += m_view->contentsY();
412  }
413 
414  outlineBox(paintInfo.p, _tx, _ty);
415 #endif
416 
417 }
418 
419 void RenderCanvas::paintBoxDecorations(PaintInfo &paintInfo, int /*_tx*/, int /*_ty*/)
420 {
421  if ((firstChild() && firstChild()->style()->visibility() == VISIBLE) || !view()) {
422  return;
423  }
424 
425  paintInfo.p->fillRect(paintInfo.r, view()->palette().color(QPalette::Active, QPalette::Base));
426 }
427 
428 void RenderCanvas::repaintRectangle(int x, int y, int w, int h, Priority p, bool f)
429 {
430  if (m_staticMode) {
431  return;
432  }
433 // qCDebug(KHTML_LOG) << "updating views contents (" << x << "/" << y << ") (" << w << "/" << h << ")";
434 
435  if (f && m_pagedMode) {
436  y += m_pageTop;
437  } else if (f && m_view) {
438  x += m_view->contentsX();
439  y += m_view->contentsY();
440  }
441 
442  QRect vr = viewRect();
443  QRect ur(x, y, w, h);
444 
445  if (m_view && ur.intersects(vr)) {
446 
447  if (p == RealtimePriority) {
448  m_view->updateContents(ur);
449  } else if (p == HighPriority) {
450  m_view->scheduleRepaint(x, y, w, h, true /*asap*/);
451  } else {
452  m_view->scheduleRepaint(x, y, w, h);
453  }
454  }
455 }
456 
457 void RenderCanvas::deferredRepaint(RenderObject *o)
458 {
459  m_dirtyChildren.append(o);
460 }
461 
462 void RenderCanvas::scheduleDeferredRepaints()
463 {
464  if (!needsFullRepaint()) {
466  for (it = m_dirtyChildren.constBegin(); it != m_dirtyChildren.constEnd(); ++it) {
467  (*it)->repaint();
468  }
469  }
470  //qCDebug(KHTML_LOG) << "scheduled deferred repaints: " << m_dirtyChildren.count() << " needed full repaint: " << needsFullRepaint();
471  m_dirtyChildren.clear();
472 }
473 
474 void RenderCanvas::repaint(Priority p)
475 {
476  if (m_view && !m_staticMode) {
477  if (p == RealtimePriority) {
478  //m_view->resizeContents(docWidth(), docHeight());
479  m_view->unscheduleRepaint();
480  if (needsLayout()) {
481  m_view->scheduleRelayout();
482  return;
483  }
484  // ### same as in repaintRectangle
485  m_view->updateContents(m_view->contentsX(), m_view->contentsY(),
486  m_view->visibleWidth(), m_view->visibleHeight());
487  } else if (p == HighPriority)
488  m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(),
489  m_view->visibleWidth(), m_view->visibleHeight(), true /*asap*/);
490  else
491  m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(),
492  m_view->visibleWidth(), m_view->visibleHeight());
493  }
494 }
495 
496 static QRect enclosingPositionedRect(RenderObject *n)
497 {
498  RenderObject *enclosingParent = n->containingBlock();
499  QRect rect(0, 0, 0, 0);
500  if (enclosingParent) {
501  int ox, oy;
502  enclosingParent->absolutePosition(ox, oy);
503  if (!enclosingParent->hasOverflowClip()) {
504  ox += enclosingParent->overflowLeft();
505  oy += enclosingParent->overflowTop();
506  }
507  rect.setX(ox);
508  rect.setY(oy);
509  rect.setWidth(enclosingParent->effectiveWidth());
510  rect.setHeight(enclosingParent->effectiveHeight());
511  }
512  return rect;
513 }
514 
515 void RenderCanvas::addStaticObject(RenderObject *o, bool pos)
516 {
517  QSet<RenderObject *> &set = pos ? m_fixedPosition : m_fixedBackground;
518  if (!o || !o->isBox() || set.contains(o)) {
519  return;
520  }
521  set.insert(o);
522  if (view()) {
523  view()->addStaticObject(pos);
524  }
525 }
526 
527 void RenderCanvas::removeStaticObject(RenderObject *o, bool pos)
528 {
529  QSet<RenderObject *> &set = pos ? m_fixedPosition : m_fixedBackground;
530  if (!o || !o->isBox() || !set.contains(o)) {
531  return;
532  }
533  set.remove(o);
534  if (view()) {
535  view()->removeStaticObject(pos);
536  }
537 }
538 
539 QRect RenderCanvas::selectionRect() const
540 {
541  RenderObject *r = m_selectionStart;
542  if (!r) {
543  return QRect();
544  }
545 
546  QRect selectionRect = enclosingPositionedRect(r);
547 
548  while (r && r != m_selectionEnd) {
549  RenderObject *n;
550  if (!(n = r->firstChild())) {
551  if (!(n = r->nextSibling())) {
552  n = r->parent();
553  while (n && !n->nextSibling()) {
554  n = n->parent();
555  }
556  if (n) {
557  n = n->nextSibling();
558  }
559  }
560  }
561  r = n;
562  if (r) {
563  selectionRect = selectionRect.united(enclosingPositionedRect(r));
564  }
565  }
566 
567  return selectionRect;
568 }
569 
570 void RenderCanvas::setSelection(RenderObject *s, int sp, RenderObject *e, int ep)
571 {
572  // Check we got valid renderobjects. www.msnbc.com and clicking
573  // around, to find the case where this happened.
574  if (!s || !e) {
575  qCWarning(KHTML_LOG) << "RenderCanvas::setSelection() called with start=" << s << " end=" << e;
576  return;
577  }
578 // qCDebug(KHTML_LOG) << "RenderCanvas::setSelection(" << s << "," << sp << "," << e << "," << ep << ")";
579 
580  bool changedSelectionBorder = (s != m_selectionStart || e != m_selectionEnd);
581 
582  // Cut out early if the selection hasn't changed.
583  if (!changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos == ep) {
584  return;
585  }
586 
587  // Record the old selected objects. Will be used later
588  // to delta against the selected objects.
589 
590  RenderObject *oldStart = m_selectionStart;
591  int oldStartPos = m_selectionStartPos;
592  RenderObject *oldEnd = m_selectionEnd;
593  int oldEndPos = m_selectionEndPos;
594  QList<RenderObject *> oldSelectedInside;
595  QList<RenderObject *> newSelectedInside;
596  RenderObject *os = oldStart;
597 
598  while (os && os != oldEnd) {
599  RenderObject *no;
600  if (!(no = os->firstChild())) {
601  if (!(no = os->nextSibling())) {
602  no = os->parent();
603  while (no && !no->nextSibling()) {
604  no = no->parent();
605  }
606  if (no) {
607  no = no->nextSibling();
608  }
609  }
610  }
611  if (os->selectionState() == SelectionInside && !oldSelectedInside.contains(os)) {
612  oldSelectedInside.append(os);
613  }
614 
615  os = no;
616  }
617  if (changedSelectionBorder) {
618  clearSelection(false);
619  }
620 
621  while (s->firstChild()) {
622  s = s->firstChild();
623  }
624  while (e->lastChild()) {
625  e = e->lastChild();
626  }
627 
628 #if 0
629  bool changedSelectionBorder = (s != m_selectionStart || e != m_selectionEnd);
630 
631  if (!changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos = ep) {
632  return;
633  }
634 #endif
635 
636  // set selection start
637  if (m_selectionStart) {
638  m_selectionStart->setIsSelectionBorder(false);
639  }
640  m_selectionStart = s;
641  if (m_selectionStart) {
642  m_selectionStart->setIsSelectionBorder(true);
643  }
644  m_selectionStartPos = sp;
645 
646  // set selection end
647  if (m_selectionEnd) {
648  m_selectionEnd->setIsSelectionBorder(false);
649  }
650  m_selectionEnd = e;
651  if (m_selectionEnd) {
652  m_selectionEnd->setIsSelectionBorder(true);
653  }
654  m_selectionEndPos = ep;
655 
656 #if 0
657  // qCDebug(KHTML_LOG) << "old selection (" << oldStart << "," << oldStartPos << "," << oldEnd << "," << oldEndPos << ")";
658  // qCDebug(KHTML_LOG) << "new selection (" << s << "," << sp << "," << e << "," << ep << ")";
659 #endif
660 
661  // update selection status of all objects between m_selectionStart and m_selectionEnd
662  RenderObject *o = s;
663 
664  while (o && o != e) {
665  o->setSelectionState(SelectionInside);
666 // qCDebug(KHTML_LOG) << "setting selected " << o << ", " << o->isText();
667  RenderObject *no;
668  if (!(no = o->firstChild()))
669  if (!(no = o->nextSibling())) {
670  no = o->parent();
671  while (no && !no->nextSibling()) {
672  no = no->parent();
673  }
674  if (no) {
675  no = no->nextSibling();
676  }
677  }
678  if (o->selectionState() == SelectionInside && !newSelectedInside.contains(o)) {
679  newSelectedInside.append(o);
680  }
681 
682  o = no;
683  }
684  s->setSelectionState(SelectionStart);
685  e->setSelectionState(SelectionEnd);
686  if (s == e) {
687  s->setSelectionState(SelectionBoth);
688  }
689 
690  if (!m_view) {
691  return;
692  }
693 
694  int i;
695  i = newSelectedInside.indexOf(s);
696  if (i != -1) {
697  newSelectedInside.removeAt(i);
698  }
699  i = newSelectedInside.indexOf(e);
700  if (i != -1) {
701  newSelectedInside.removeAt(i);
702  }
703 
704  QRect updateRect;
705 
706  // Don't use repaint() because it will cause all rects to
707  // be united (see khtmlview::scheduleRepaint()). Instead
708  // just draw damage rects for objects that have a change
709  // in selection state.
710  // ### for Qt, updateContents will unite them, too. This has to be
711  // circumvented somehow (LS)
712 
713  // Are any of the old fully selected objects not in the new selection?
714  // If so we have to draw them.
715  // Could be faster by building list of non-intersecting rectangles rather
716  // than unioning rectangles.
717  QListIterator<RenderObject *> oldIterator(oldSelectedInside);
718  bool firstRect = true;
719  while (oldIterator.hasNext()) {
720  o = oldIterator.next();
721  if (!newSelectedInside.contains(o)) {
722  if (firstRect) {
723  updateRect = enclosingPositionedRect(o);
724  firstRect = false;
725  } else {
726  updateRect = updateRect.united(enclosingPositionedRect(o));
727  }
728  }
729  }
730  if (!firstRect) {
731  m_view->updateContents(updateRect);
732  }
733 
734  // Are any of the new fully selected objects not in the previous selection?
735  // If so we have to draw them.
736  // Could be faster by building list of non-intersecting rectangles rather
737  // than unioning rectangles.
738  QListIterator<RenderObject *> newIterator(newSelectedInside);
739  firstRect = true;
740  while (newIterator.hasNext()) {
741  o = newIterator.next();
742  if (!oldSelectedInside.contains(o)) {
743  if (firstRect) {
744  updateRect = enclosingPositionedRect(o);
745  firstRect = false;
746  } else {
747  updateRect = updateRect.united(enclosingPositionedRect(o));
748  }
749  }
750  }
751  if (!firstRect) {
752  m_view->updateContents(updateRect);
753  }
754 
755  // Is the new starting object different, or did the position in the starting
756  // element change? If so we have to draw it.
757  if (oldStart != m_selectionStart ||
758  (oldStart == oldEnd && (oldStartPos != m_selectionStartPos || oldEndPos != m_selectionEndPos)) ||
759  (oldStart == m_selectionStart && oldStartPos != m_selectionStartPos)) {
760  m_view->updateContents(enclosingPositionedRect(m_selectionStart));
761  }
762 
763  // Draw the old selection start object if it's different than the new selection
764  // start object.
765  if (oldStart && oldStart != m_selectionStart) {
766  m_view->updateContents(enclosingPositionedRect(oldStart));
767  }
768 
769  // Does the selection span objects and is the new end object different, or did the position
770  // in the end element change? If so we have to draw it.
771  if (/*(oldStart != oldEnd || !oldEnd) &&*/
772  (oldEnd != m_selectionEnd ||
773  (oldEnd == m_selectionEnd && oldEndPos != m_selectionEndPos))) {
774  m_view->updateContents(enclosingPositionedRect(m_selectionEnd));
775  }
776 
777  // Draw the old selection end object if it's different than the new selection
778  // end object.
779  if (oldEnd && oldEnd != m_selectionEnd) {
780  m_view->updateContents(enclosingPositionedRect(oldEnd));
781  }
782 }
783 
784 void RenderCanvas::clearSelection(bool doRepaint)
785 {
786  // update selection status of all objects between m_selectionStart and m_selectionEnd
787  RenderObject *o = m_selectionStart;
788  while (o && o != m_selectionEnd) {
789  if (o->selectionState() != SelectionNone)
790  if (doRepaint) {
791  o->repaint();
792  }
793  o->setSelectionState(SelectionNone);
794  o->repaint();
795  RenderObject *no;
796  if (!(no = o->firstChild()))
797  if (!(no = o->nextSibling())) {
798  no = o->parent();
799  while (no && !no->nextSibling()) {
800  no = no->parent();
801  }
802  if (no) {
803  no = no->nextSibling();
804  }
805  }
806  o = no;
807  }
808  if (m_selectionEnd) {
809  m_selectionEnd->setSelectionState(SelectionNone);
810  if (doRepaint) {
811  m_selectionEnd->repaint();
812  }
813  }
814 
815  // set selection start & end to 0
816  if (m_selectionStart) {
817  m_selectionStart->setIsSelectionBorder(false);
818  }
819  m_selectionStart = nullptr;
820  m_selectionStartPos = -1;
821 
822  if (m_selectionEnd) {
823  m_selectionEnd->setIsSelectionBorder(false);
824  }
825  m_selectionEnd = nullptr;
826  m_selectionEndPos = -1;
827 }
828 
829 void RenderCanvas::selectionStartEnd(int &spos, int &epos)
830 {
831  spos = m_selectionStartPos;
832  epos = m_selectionEndPos;
833 }
834 
835 QRect RenderCanvas::viewRect() const
836 {
837  if (m_pagedMode)
838  if (m_pageTop == m_pageBottom) {
839  // qCDebug(KHTML_LOG) << "viewRect: " << QRect(0, m_pageTop, m_width, m_height);
840  return QRect(0, m_pageTop, m_width, m_height);
841  } else {
842  // qCDebug(KHTML_LOG) << "viewRect: " << QRect(0, m_pageTop, m_width, m_pageBottom - m_pageTop);
843  return QRect(0, m_pageTop, m_width, m_pageBottom - m_pageTop);
844  }
845  else if (m_view) {
846  const int z = m_view->zoomLevel() ? m_view->zoomLevel() : 100;
847  return QRect(m_view->contentsX() * 100 / z, m_view->contentsY() * 100 / z,
848  m_view->visibleWidth(), m_view->visibleHeight());
849  } else {
850  return QRect(0, 0, m_rootWidth, m_rootHeight);
851  }
852 }
853 
854 int RenderCanvas::docHeight() const
855 {
856  if (m_cachedDocHeight != -1) {
857  return m_cachedDocHeight;
858  }
859 
860  int h;
861  if (m_pagedMode || !m_view) {
862  h = m_height;
863  } else {
864  h = 0;
865  }
866 
867  RenderObject *fc = firstChild();
868  if (fc) {
869  int dh = fc->overflowHeight() + fc->marginTop() + fc->marginBottom();
870  int lowestPos = fc->lowestPosition(false);
871 // qCDebug(KHTML_LOG) << "h " << h << " lowestPos " << lowestPos << " dh " << dh << " fc->rh " << fc->effectiveHeight() << " fc->height() " << fc->height();
872  if (lowestPos > dh) {
873  dh = lowestPos;
874  }
875  lowestPos = lowestAbsolutePosition();
876  if (lowestPos > dh) {
877  dh = lowestPos;
878  }
879  if (dh > h) {
880  h = dh;
881  }
882  }
883 
884  RenderLayer *layer = m_layer;
885  h = qMax(h, layer->yPos() + layer->height());
886 // 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();
887  return h;
888 }
889 
890 int RenderCanvas::docWidth() const
891 {
892  if (m_cachedDocWidth != -1) {
893  return m_cachedDocWidth;
894  }
895 
896  int w;
897  if (m_pagedMode || !m_view) {
898  w = m_width;
899  } else {
900  w = 0;
901  }
902 
903  RenderObject *fc = firstChild();
904  if (fc) {
905  // ow: like effectiveWidth() but without the negative
906  const int ow = fc->hasOverflowClip() ? fc->width() : fc->overflowWidth();
907  int dw = ow + fc->marginLeft() + fc->marginRight();
908  int rightmostPos = fc->rightmostPosition(false);
909 // qCDebug(KHTML_LOG) << "w " << w << " rightmostPos " << rightmostPos << " dw " << dw << " fc->rw " << fc->effectiveWidth() << " fc->width() " << fc->width();
910  if (rightmostPos > dw) {
911  dw = rightmostPos;
912  }
913  rightmostPos = rightmostAbsolutePosition();
914  if (rightmostPos > dw) {
915  dw = rightmostPos;
916  }
917  if (dw > w) {
918  w = dw;
919  }
920  }
921 
922  RenderLayer *layer = m_layer;
923  w = qMax(w, layer->xPos() + layer->width());
924 // 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();
925  return w;
926 }
927 
928 RenderPage *RenderCanvas::page()
929 {
930  if (!m_page) {
931  m_page = new RenderPage(this);
932  }
933  return m_page;
934 }
935 
936 void RenderCanvas::updateInvalidatedFonts()
937 {
938  for (RenderObject *o = firstChild(); o; o = o->nextRenderer()) {
939  if (o->style()->htmlFont().isInvalidated()) {
940  o->setNeedsLayoutAndMinMaxRecalc();
941 // qCDebug(KHTML_LOG) << "updating object using invalid font" << o->style()->htmlFont().getFontDef().family << o->information();
942  }
943  }
944 }
ScrollBarAsNeeded
void setHeight(int height)
int width() const const
This file is part of the HTML rendering engine for KDE.
void removeAt(int i)
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
QSet::iterator insert(const T &value)
a cached image
Definition: loader.h:359
int indexOf(const T &value, int from) const const
int elapsed() const const
void append(const T &value)
int effectiveWidth() const
Returns the width that is effectively considered when contemplating the object as a whole – usually ...
void setWidth(int width)
MESSAGECORE_EXPORT KMime::Content * firstChild(const KMime::Content *node)
QRegion intersected(const QRegion &r) const const
bool contains(const T &value) const const
bool remove(const T &value)
int height() const const
Base Class for all rendering tree objects.
void start()
int effectiveHeight() const
Returns the height that is effectively considered when contemplating the object as a whole – usually...
QRect united(const QRect &rectangle) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:07 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.