KHtml

render_object.cpp
1 /**
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 1999-2003 Lars Knoll ([email protected])
5  * (C) 1999 Antti Koivisto ([email protected])
6  * (C) 2000-2003 Dirk Mueller ([email protected])
7  * (C) 2004-2008 Apple Computer, Inc.
8  * (C) 2006 Germain Garand <[email protected]>
9  * (C) 2008-2009 Fredrik Höglund <[email protected]>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB. If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "rendering/render_object.h"
29 #include "rendering/render_table.h"
30 #include "rendering/render_list.h"
31 #include "rendering/render_canvas.h"
32 #include "rendering/render_block.h"
33 #include "rendering/render_arena.h"
34 #include "rendering/render_layer.h"
35 #include "rendering/render_line.h"
36 #include "rendering/render_inline.h"
37 #include "rendering/render_text.h"
38 #include "rendering/render_replaced.h"
39 #include "rendering/render_generated.h"
40 #include "rendering/counter_tree.h"
41 
42 #include "xml/dom_elementimpl.h"
43 #include "dom/dom_doc.h"
44 #include "misc/loader.h"
45 #include "misc/borderarcstroker.h"
46 
47 #include "khtml_debug.h"
48 #include <QPainter>
49 #include "khtmlview.h"
50 #include <khtml_part.h>
51 #include <QPaintEngine>
52 
53 using namespace DOM;
54 using namespace khtml;
55 
56 #define RED_LUMINOSITY 30
57 #define GREEN_LUMINOSITY 59
58 #define BLUE_LUMINOSITY 11
59 #define INTENSITY_FACTOR 25
60 #define LIGHT_FACTOR 0
61 #define LUMINOSITY_FACTOR 75
62 
63 #define MAX_COLOR 255
64 #define COLOR_DARK_THRESHOLD 51
65 #define COLOR_LIGHT_THRESHOLD 204
66 
67 #define COLOR_LITE_BS_FACTOR 45
68 #define COLOR_LITE_TS_FACTOR 70
69 
70 #define COLOR_DARK_BS_FACTOR 30
71 #define COLOR_DARK_TS_FACTOR 50
72 
73 #define LIGHT_GRAY qRgb(192, 192, 192)
74 #define DARK_GRAY qRgb(96, 96, 96)
75 
76 #ifndef NDEBUG
77 static void *baseOfRenderObjectBeingDeleted;
78 #endif
79 
80 QCache<quint64, QPixmap> *RenderObject::s_dashedLineCache = nullptr;
81 
82 void RenderObject::cleanup()
83 {
84  delete s_dashedLineCache;
85  s_dashedLineCache = nullptr;
86 }
87 
88 //#define MASK_DEBUG
89 
90 void *RenderObject::operator new(size_t sz, RenderArena *renderArena) throw()
91 {
92  return renderArena->allocate(sz);
93 }
94 
95 void RenderObject::operator delete(void *ptr, size_t sz)
96 {
97  assert(baseOfRenderObjectBeingDeleted == ptr);
98 
99 #ifdef KHTML_USE_ARENA_ALLOCATOR
100  // Stash size where detach can find it.
101  *(size_t *)ptr = sz;
102 #endif
103 }
104 
105 RenderObject *RenderObject::createObject(DOM::NodeImpl *node, RenderStyle *style)
106 {
107  RenderObject *o = nullptr;
108  khtml::RenderArena *arena = node->document()->renderArena();
109  switch (style->display()) {
110  case NONE:
111  break;
112  case INLINE:
113  o = new(arena) RenderInline(node);
114  break;
115  case BLOCK:
116  o = new(arena) RenderBlock(node);
117  break;
118  case INLINE_BLOCK:
119  o = new(arena) RenderBlock(node);
120  break;
121  case LIST_ITEM:
122  o = new(arena) RenderListItem(node);
123  break;
124  case RUN_IN:
125  case COMPACT:
126  o = new(arena) RenderBlock(node);
127  break;
128  case TABLE:
129  case INLINE_TABLE:
130  style->setFlowAroundFloats(true);
131  o = new(arena) RenderTable(node);
132  break;
133  case TABLE_ROW_GROUP:
134  case TABLE_HEADER_GROUP:
135  case TABLE_FOOTER_GROUP:
136  o = new(arena) RenderTableSection(node);
137  break;
138  case TABLE_ROW:
139  o = new(arena) RenderTableRow(node);
140  break;
141  case TABLE_COLUMN_GROUP:
142  case TABLE_COLUMN:
143  o = new(arena) RenderTableCol(node);
144  break;
145  case TABLE_CELL:
146  o = new(arena) RenderTableCell(node);
147  break;
148  case TABLE_CAPTION:
149  o = new(arena) RenderBlock(node);
150  break;
151  }
152  return o;
153 }
154 
155 RenderObject::RenderObject(DOM::NodeImpl *node)
156  : CachedObjectClient(),
157  m_style(nullptr),
158  m_node(node),
159  m_parent(nullptr),
160  m_previous(nullptr),
161  m_next(nullptr),
162  m_verticalPosition(PositionUndefined),
163  m_needsLayout(false),
164  m_normalChildNeedsLayout(false),
165  m_markedForRepaint(false),
166  m_posChildNeedsLayout(false),
167  m_minMaxKnown(false),
168  m_floating(false),
169 
170  m_positioned(false),
171  m_relPositioned(false),
172  m_paintBackground(false),
173 
174  m_isAnonymous(node->isDocumentNode()),
175  m_recalcMinMax(false),
176  m_isText(false),
177  m_inline(true),
178  m_attached(false),
179 
180  m_replaced(false),
181  m_mouseInside(false),
182  m_hasFirstLine(false),
183  m_isSelectionBorder(false),
184  m_isRoot(false),
185  m_afterPageBreak(false),
186  m_needsPageClear(false),
187  m_containsPageBreak(false),
188  m_hasOverflowClip(false),
189  m_inPosObjectList(false),
190  m_doNotDelete(false)
191 {
192  assert(node);
193  if (node->document()->documentElement() == node) {
194  setIsRoot(true);
195  }
196 }
197 
198 RenderObject::~RenderObject()
199 {
200  const BackgroundLayer *bgLayer = m_style->backgroundLayers();
201  while (bgLayer) {
202  if (bgLayer->backgroundImage()) {
203  bgLayer->backgroundImage()->deref(this);
204  }
205  bgLayer = bgLayer->next();
206  }
207 
208  m_style->deref();
209 }
210 
211 RenderObject *RenderObject::objectBelow() const
212 {
213  RenderObject *obj = firstChild();
214  if (!obj) {
215  obj = nextSibling();
216  if (!obj) {
217  obj = parent();
218  while (obj && !obj->nextSibling()) {
219  obj = obj->parent();
220  }
221  if (obj) {
222  obj = obj->nextSibling();
223  }
224  }
225  }
226  return obj;
227 }
228 
229 RenderObject *RenderObject::objectAbove() const
230 {
231  RenderObject *obj = previousSibling();
232  if (!obj) {
233  return parent();
234  }
235 
236  RenderObject *last = obj->lastChild();
237  while (last) {
238  obj = last;
239  last = last->lastChild();
240  }
241  return obj;
242 }
243 /*
244 bool RenderObject::isRoot() const
245 {
246  return !isAnonymous() &&
247  element()->document()->documentElement() == element();
248 }*/
249 
250 bool RenderObject::isHR() const
251 {
252  return element() && element()->id() == ID_HR;
253 }
254 bool RenderObject::isWordBreak() const
255 {
256  return element() && element()->id() == ID_WBR;
257 }
258 bool RenderObject::isHTMLMarquee() const
259 {
260  return element() && element()->renderer() == this && element()->id() == ID_MARQUEE;
261 }
262 
263 void RenderObject::addChild(RenderObject *, RenderObject *)
264 {
265  KHTMLAssert(0);
266 }
267 
268 RenderObject *RenderObject::removeChildNode(RenderObject *)
269 {
270  KHTMLAssert(0);
271  return nullptr;
272 }
273 
274 void RenderObject::removeChild(RenderObject *)
275 {
276  KHTMLAssert(0);
277 }
278 
279 void RenderObject::appendChildNode(RenderObject *)
280 {
281  KHTMLAssert(0);
282 }
283 
284 void RenderObject::insertChildNode(RenderObject *, RenderObject *)
285 {
286  KHTMLAssert(0);
287 }
288 
289 RenderObject *RenderObject::nextRenderer() const
290 {
291  if (firstChild()) {
292  return firstChild();
293  } else if (nextSibling()) {
294  return nextSibling();
295  } else {
296  const RenderObject *r = this;
297  while (r && !r->nextSibling()) {
298  r = r->parent();
299  }
300  if (r) {
301  return r->nextSibling();
302  }
303  }
304  return nullptr;
305 }
306 
307 RenderObject *RenderObject::previousRenderer() const
308 {
309  if (previousSibling()) {
310  RenderObject *r = previousSibling();
311  while (r->lastChild()) {
312  r = r->lastChild();
313  }
314  return r;
315  } else if (parent()) {
316  return parent();
317  } else {
318  return nullptr;
319  }
320 }
321 
322 bool RenderObject::isEditable() const
323 {
324  RenderText *textRenderer = nullptr;
325  if (isText()) {
326  textRenderer = static_cast<RenderText *>(const_cast<RenderObject *>(this));
327  }
328 
329  return style()->visibility() == VISIBLE &&
330  element() && element()->isContentEditable() &&
331  ((isBlockFlow() && !firstChild()) ||
332  isReplaced() ||
333  isBR() ||
334  (textRenderer && textRenderer->firstTextBox()));
335 }
336 
337 RenderObject *RenderObject::nextEditable() const
338 {
339  RenderObject *r = const_cast<RenderObject *>(this);
340  RenderObject *n = firstChild();
341  if (n) {
342  while (n) {
343  r = n;
344  n = n->firstChild();
345  }
346  if (r->isEditable()) {
347  return r;
348  } else {
349  return r->nextEditable();
350  }
351  }
352  n = r->nextSibling();
353  if (n) {
354  r = n;
355  while (n) {
356  r = n;
357  n = n->firstChild();
358  }
359  if (r->isEditable()) {
360  return r;
361  } else {
362  return r->nextEditable();
363  }
364  }
365  n = r->parent();
366  while (n) {
367  r = n;
368  n = r->nextSibling();
369  if (n) {
370  r = n;
371  n = r->firstChild();
372  while (n) {
373  r = n;
374  n = n->firstChild();
375  }
376  if (r->isEditable()) {
377  return r;
378  } else {
379  return r->nextEditable();
380  }
381  }
382  n = r->parent();
383  }
384  return nullptr;
385 }
386 
387 RenderObject *RenderObject::previousEditable() const
388 {
389  RenderObject *r = const_cast<RenderObject *>(this);
390  RenderObject *n = firstChild();
391  if (n) {
392  while (n) {
393  r = n;
394  n = n->lastChild();
395  }
396  if (r->isEditable()) {
397  return r;
398  } else {
399  return r->previousEditable();
400  }
401  }
402  n = r->previousSibling();
403  if (n) {
404  r = n;
405  while (n) {
406  r = n;
407  n = n->lastChild();
408  }
409  if (r->isEditable()) {
410  return r;
411  } else {
412  return r->previousEditable();
413  }
414  }
415  n = r->parent();
416  while (n) {
417  r = n;
418  n = r->previousSibling();
419  if (n) {
420  r = n;
421  n = r->lastChild();
422  while (n) {
423  r = n;
424  n = n->lastChild();
425  }
426  if (r->isEditable()) {
427  return r;
428  } else {
429  return r->previousEditable();
430  }
431  }
432  n = r->parent();
433  }
434  return nullptr;
435 }
436 
437 RenderObject *RenderObject::firstLeafChild() const
438 {
439  RenderObject *r = firstChild();
440  while (r) {
441  RenderObject *n = nullptr;
442  n = r->firstChild();
443  if (!n) {
444  break;
445  }
446  r = n;
447  }
448  return r;
449 }
450 
451 RenderObject *RenderObject::lastLeafChild() const
452 {
453  RenderObject *r = lastChild();
454  while (r) {
455  RenderObject *n = nullptr;
456  n = r->lastChild();
457  if (!n) {
458  break;
459  }
460  r = n;
461  }
462  return r;
463 }
464 
465 static void addLayers(RenderObject *obj, RenderLayer *parentLayer, RenderObject *&newObject,
466  RenderLayer *&beforeChild)
467 {
468  if (obj->layer()) {
469  if (!beforeChild && newObject) {
470  // We need to figure out the layer that follows newObject. We only do
471  // this the first time we find a child layer, and then we update the
472  // pointer values for newObject and beforeChild used by everyone else.
473  beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
474  newObject = nullptr;
475  }
476  parentLayer->addChild(obj->layer(), beforeChild);
477  return;
478  }
479 
480  for (RenderObject *curr = obj->firstChild(); curr; curr = curr->nextSibling()) {
481  addLayers(curr, parentLayer, newObject, beforeChild);
482  }
483 }
484 
485 void RenderObject::addLayers(RenderLayer *parentLayer, RenderObject *newObject)
486 {
487  if (!parentLayer) {
488  return;
489  }
490 
491  RenderObject *object = newObject;
492  RenderLayer *beforeChild = nullptr;
493  ::addLayers(this, parentLayer, object, beforeChild);
494 }
495 
496 void RenderObject::removeLayers(RenderLayer *parentLayer)
497 {
498  if (!parentLayer) {
499  return;
500  }
501 
502  if (layer()) {
503  parentLayer->removeChild(layer());
504  return;
505  }
506 
507  for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
508  curr->removeLayers(parentLayer);
509  }
510 }
511 
512 void RenderObject::moveLayers(RenderLayer *oldParent, RenderLayer *newParent)
513 {
514  if (!newParent) {
515  return;
516  }
517 
518  if (layer()) {
519  if (oldParent) {
520  oldParent->removeChild(layer());
521  }
522  newParent->addChild(layer());
523  return;
524  }
525 
526  for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
527  curr->moveLayers(oldParent, newParent);
528  }
529 }
530 
531 RenderLayer *RenderObject::findNextLayer(RenderLayer *parentLayer, RenderObject *startPoint,
532  bool checkParent)
533 {
534  // Error check the parent layer passed in. If it's null, we can't find anything.
535  if (!parentLayer) {
536  return nullptr;
537  }
538 
539  // Step 1: If our layer is a child of the desired parent, then return our layer.
540  RenderLayer *ourLayer = layer();
541  if (ourLayer && ourLayer->parent() == parentLayer) {
542  return ourLayer;
543  }
544 
545  // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
546  // into our siblings trying to find the next layer whose parent is the desired parent.
547  if (!ourLayer || ourLayer == parentLayer) {
548  for (RenderObject *curr = startPoint ? startPoint->nextSibling() : firstChild();
549  curr; curr = curr->nextSibling()) {
550  RenderLayer *nextLayer = curr->findNextLayer(parentLayer, nullptr, false);
551  if (nextLayer) {
552  return nextLayer;
553  }
554  }
555  }
556 
557  // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
558  // find anything.
559  if (parentLayer == ourLayer) {
560  return nullptr;
561  }
562 
563  // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
564  // follow us to see if we can locate a layer.
565  if (checkParent && parent()) {
566  return parent()->findNextLayer(parentLayer, this, true);
567  }
568 
569  return nullptr;
570 }
571 
572 RenderLayer *RenderObject::enclosingLayer() const
573 {
574  const RenderObject *curr = this;
575  while (curr) {
576  RenderLayer *layer = curr->layer();
577  if (layer) {
578  return layer;
579  }
580  curr = curr->parent();
581  }
582  return nullptr;
583 }
584 
585 RenderLayer *RenderObject::enclosingStackingContext() const
586 {
587  RenderLayer *l = enclosingLayer();
588  while (l && !l->isStackingContext()) {
589  l = l->parent();
590  }
591  return l;
592 }
593 
594 QRectF RenderObject::clientRectToViewport(const QRectF &rect)
595 {
596  int offsetX = document()->part()->view()->contentsX();
597  int offsetY = document()->part()->view()->contentsY();
598 
599  QRectF newRect(rect.x() - offsetX, rect.y() - offsetY,
600  rect.width(), rect.height());
601 
602  return newRect;
603 }
604 
605 QList<QRectF> RenderObject::getClientRects()
606 {
607  QList<QRectF> ret;
608 
609  int x = 0;
610  int y = 0;
611  absolutePosition(x, y);
612 
613  QRectF rect(x, y, width(), height());
614  ret.append(clientRectToViewport(rect));
615 
616  return ret;
617 }
618 
619 int RenderObject::offsetLeft() const
620 {
621  if (isBody()) {
622  return 0;
623  }
624 
625  int x, dummy;
626  RenderObject *offsetPar = offsetParent();
627  if (!offsetPar || offsetPar->isBody()) {
628  if (style()->position() == PFIXED) {
629  return xPos();
630  } else {
631  absolutePosition(x, dummy);
632  return x;
633  }
634  }
635 
636  x = xPos() - offsetPar->borderLeft();
637  if (isPositioned()) {
638  return x;
639  }
640 
641  if (isRelPositioned()) {
642  int y = 0;
643  static_cast<const RenderBox *>(this)->relativePositionOffset(x, y);
644  }
645 
646  for (RenderObject *curr = parent();
647  curr && curr != offsetPar;
648  curr = curr->parent()) {
649  x += curr->xPos();
650  }
651 
652  return x;
653 }
654 
655 int RenderObject::offsetTop() const
656 {
657  if (isBody()) {
658  return 0;
659  }
660 
661  int y, dummy;
662  RenderObject *offsetPar = offsetParent();
663  if (!offsetPar || offsetPar->isBody()) {
664  if (style()->position() == PFIXED) {
665  return yPos();
666  } else {
667  absolutePosition(dummy, y);
668  return y;
669  }
670  }
671 
672  y = yPos() - offsetPar->borderTop();
673  if (isPositioned()) {
674  return y;
675  }
676 
677  if (isRelPositioned()) {
678  int x = 0;
679  static_cast<const RenderBox *>(this)->relativePositionOffset(x, y);
680  }
681  for (RenderObject *curr = parent();
682  curr && curr != offsetPar;
683  curr = curr->parent()) {
684  y += curr->yPos();
685  }
686 
687  return y;
688 }
689 
690 RenderObject *RenderObject::offsetParent() const
691 {
692  if (isBody() || style()->position() == PFIXED) {
693  return nullptr;
694  }
695 
696  // can't really use containing blocks here (#113280)
697  bool skipTables = isPositioned() || isRelPositioned();
698  bool strict = !style()->htmlHacks();
699  RenderObject *curr = parent();
700  while (curr && (!curr->element() ||
701  (!curr->isPositioned() && !curr->isRelPositioned() &&
702  !(strict && skipTables ? curr->isRoot() : curr->isBody())))) {
703  if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable())) {
704  break;
705  }
706  curr = curr->parent();
707  }
708  return curr;
709 }
710 
711 // IE extensions.
712 // clientWidth and clientHeight represent the interior of an object
713 short RenderObject::clientWidth() const
714 {
715  return width() - borderLeft() - borderRight() -
716  (layer() ? layer()->verticalScrollbarWidth() : 0);
717 }
718 
719 int RenderObject::clientLeft() const
720 {
721  return borderLeft();
722 }
723 
724 int RenderObject::clientTop() const
725 {
726  return borderTop();
727 }
728 
729 int RenderObject::clientHeight() const
730 {
731  return height() - borderTop() - borderBottom() -
732  (layer() ? layer()->horizontalScrollbarHeight() : 0);
733 }
734 
735 // scrollWidth/scrollHeight is the size including the overflow area
736 short RenderObject::scrollWidth() const
737 {
738  return (hasOverflowClip() && layer()) ? layer()->scrollWidth() : overflowWidth() - overflowLeft();
739 }
740 
741 int RenderObject::scrollHeight() const
742 {
743  return (hasOverflowClip() && layer()) ? layer()->scrollHeight() : overflowHeight() - overflowTop();
744 }
745 
746 void RenderObject::updatePixmap(const QRect & /*r*/, CachedImage *image)
747 {
748 #ifdef __GNUC__
749 #warning "FIXME: Check if complete!"
750 #endif
751  //repaint bg when it finished loading
752  if (image && parent() && style() && style()->backgroundLayers()->containsImage(image)) {
753  isBody() ? canvas()->repaint() : repaint();
754  }
755 }
756 
757 void RenderObject::setNeedsLayout(bool b, bool markParents)
758 {
759  bool alreadyNeededLayout = m_needsLayout;
760  m_needsLayout = b;
761  if (b) {
762  if (!alreadyNeededLayout && markParents && m_parent) {
763  dirtyFormattingContext(false);
764  markContainingBlocksForLayout();
765  }
766  } else {
767  m_posChildNeedsLayout = false;
768  m_normalChildNeedsLayout = false;
769  }
770 }
771 
772 void RenderObject::setChildNeedsLayout(bool b, bool markParents)
773 {
774  bool alreadyNeededLayout = m_normalChildNeedsLayout;
775  m_normalChildNeedsLayout = b;
776  if (b) {
777  if (!alreadyNeededLayout && markParents) {
778  markContainingBlocksForLayout();
779  }
780  } else {
781  m_posChildNeedsLayout = false;
782  m_normalChildNeedsLayout = false;
783  }
784 }
785 
786 void RenderObject::markContainingBlocksForLayout()
787 {
788  RenderObject *o = container();
789  RenderObject *last = this;
790 
791  while (o) {
792  if (!last->isText() && (last->style()->position() == PFIXED || last->style()->position() == PABSOLUTE)) {
793  if (o->m_posChildNeedsLayout) {
794  return;
795  }
796  o->m_posChildNeedsLayout = true;
797  } else {
798  if (o->m_normalChildNeedsLayout) {
799  return;
800  }
801  o->m_normalChildNeedsLayout = true;
802  }
803 
804  last = o;
805  o = o->container();
806  }
807 
808  last->scheduleRelayout();
809 }
810 
811 RenderBlock *RenderObject::containingBlock() const
812 {
813  if (isTableCell()) {
814  return static_cast<RenderBlock *>(parent()->parent()->parent());
815  }
816  if (isCanvas()) {
817  return const_cast<RenderBlock *>(static_cast<const RenderBlock *>(this));
818  }
819 
820  RenderObject *o = parent();
821  if (m_style->position() == PFIXED) {
822  while (o && !o->isCanvas()) {
823  o = o->parent();
824  }
825  } else if (m_style->position() == PABSOLUTE) {
826  while (o &&
827  (o->style()->position() == PSTATIC || (o->isInline() && !o->isReplaced())) && !o->isCanvas()) {
828  // for relpos inlines, return the nearest block - it will host the positioned objects list
829  if (o->isInline() && !o->isReplaced() && o->style()->position() == PRELATIVE) {
830  return o->containingBlock();
831  }
832  o = o->parent();
833  }
834  } else {
835  while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection() ||
836  o->isTableCol() || o->isFrameSet() ||
837  o->isSVGContainer() || o->isSVGRoot())) // for svg
838 
839  {
840  o = o->parent();
841  }
842  }
843  // this is just to make sure we return a valid element.
844  // the case below should never happen...
845  if (!o || !o->isRenderBlock()) {
846  if (!isCanvas()) {
847 #ifndef NDEBUG
848  qCDebug(KHTML_LOG) << this << ": " << renderName() << "(RenderObject): No containingBlock!";
849  const RenderObject *p = this;
850  while (p->parent()) {
851  p = p->parent();
852  }
853  p->printTree();
854 #endif
855  }
856  return canvas(); // likely wrong, but better than a crash
857  }
858 
859  return static_cast<RenderBlock *>(o);
860 }
861 
862 short RenderObject::containingBlockWidth(RenderObject *) const
863 {
864  // ###
865  return containingBlock()->contentWidth();
866 }
867 
868 int RenderObject::containingBlockHeight(RenderObject *) const
869 {
870  // ###
871  return containingBlock()->contentHeight();
872 }
873 
874 bool RenderObject::sizesToMaxWidth() const
875 {
876  // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
877  // but they allow text to sit on the same line as the marquee.
878  if (isFloating() || isCompact() ||
879  (isInlineBlockOrInlineTable() && !isHTMLMarquee()) ||
880  (element() && (element()->id() == ID_BUTTON || element()->id() == ID_LEGEND))) {
881  return true;
882  }
883 
884  // Children of a horizontal marquee do not fill the container by default.
885  // FIXME: Need to deal with MAUTO value properly. It could be vertical.
886  if (parent()->style()->overflowX() == OMARQUEE) {
887  EMarqueeDirection dir = parent()->style()->marqueeDirection();
888  if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT) {
889  return true;
890  }
891  }
892 
893 #ifdef APPLE_CHANGES // ### what the heck is a flexbox?
894  // Flexible horizontal boxes lay out children at their maxwidths. Also vertical boxes
895  // that don't stretch their kids lay out their children at their maxwidths.
896  if (parent()->isFlexibleBox() &&
897  (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH)) {
898  return true;
899  }
900 #endif
901 
902  return false;
903 }
904 
905 // from Mozilla's nsCSSColorUtils.cpp
906 static int brightness(int red, int green, int blue)
907 {
908 
909  int intensity = (red + green + blue) / 3;
910 
911  int luminosity =
912  ((RED_LUMINOSITY * red) / 100) +
913  ((GREEN_LUMINOSITY * green) / 100) +
914  ((BLUE_LUMINOSITY * blue) / 100);
915 
916  return ((intensity * INTENSITY_FACTOR) +
917  (luminosity * LUMINOSITY_FACTOR)) / 100;
918 }
919 
920 static void calc3DColor(QColor &color, bool darken)
921 {
922  int rb = color.red();
923  int gb = color.green();
924  int bb = color.blue();
925  int a = color.alpha();
926 
927  int brightness_ = brightness(rb, gb, bb);
928 
929  int f0, f1;
930  if (brightness_ < COLOR_DARK_THRESHOLD) {
931  f0 = COLOR_DARK_BS_FACTOR;
932  f1 = COLOR_DARK_TS_FACTOR;
933  } else if (brightness_ > COLOR_LIGHT_THRESHOLD) {
934  f0 = COLOR_LITE_BS_FACTOR;
935  f1 = COLOR_LITE_TS_FACTOR;
936  } else {
937  f0 = COLOR_DARK_BS_FACTOR +
938  (brightness_ *
939  (COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR) / MAX_COLOR);
940  f1 = COLOR_DARK_TS_FACTOR +
941  (brightness_ *
942  (COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR) / MAX_COLOR);
943  }
944 
945  if (darken) {
946  int r = rb - (f0 * rb / 100);
947  int g = gb - (f0 * gb / 100);
948  int b = bb - (f0 * bb / 100);
949  if ((r == rb) && (g == gb) && (b == bb)) {
950  color = (color == Qt::black) ? QColor(DARK_GRAY) : QColor(Qt::black);
951  } else {
952  color.setRgb(r, g, b);
953  }
954  } else {
955  int r = qMin(rb + (f1 * (MAX_COLOR - rb) / 100), 255);
956  int g = qMin(gb + (f1 * (MAX_COLOR - gb) / 100), 255);
957  int b = qMin(bb + (f1 * (MAX_COLOR - bb) / 100), 255);
958  if ((r == rb) && (g == gb) && (b == bb)) {
959  color = (color == Qt::white) ? QColor(LIGHT_GRAY) : QColor(Qt::white);
960  } else {
961  color.setRgb(r, g, b);
962  }
963  }
964  color.setAlpha(a);
965 }
966 
967 void RenderObject::drawBorder(QPainter *p, int x1, int y1, int x2, int y2,
968  BorderSide s, QColor c, const QColor &textcolor, EBorderStyle style,
969  int adjbw1, int adjbw2, bool invalidisInvert, qreal *nextDashOffset)
970 {
971  if (nextDashOffset && style != DOTTED && style != DASHED) {
972  *nextDashOffset = 0;
973  }
974 
975  if (p->hasClipping() && !p->clipRegion().boundingRect().intersects(QRect(x1, y1, x2 - x1, y2 - y1))) {
976  if (nextDashOffset && (style == DOTTED || style == DASHED)) {
977  *nextDashOffset += (s == BSTop || s == BSBottom) ? (x2 - x1) : (y2 - y1);
978  }
979  return;
980  }
981 
982  int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1);
983 
984  if (style == DOUBLE && width < 3) {
985  style = SOLID;
986  }
987 
988  if (!c.isValid()) {
989  if (invalidisInvert) {
990  // handle 'outline-color: invert'
993  c = Qt::white;
994  } else {
995  // 'invert' is not supported on this platform (for instance XRender)
996  // CSS3 UI 8.4: If the UA does not support the 'invert' value then the initial value of
997  // the 'outline-color' property is the 'currentColor' [CSS3COLOR] keyword.
998  c = m_style->color();
999  }
1000  } else {
1001  if (style == INSET || style == OUTSET || style == RIDGE || style ==
1002  GROOVE) {
1003  c = Qt::white;
1004  } else {
1005  c = textcolor;
1006  }
1007  }
1008  }
1009 
1010  switch (style) {
1011  case BNATIVE:
1012  case BNONE:
1013  case BHIDDEN:
1014  // should not happen
1015  if (invalidisInvert && p->compositionMode() == QPainter::CompositionMode_Difference) {
1017  }
1018 
1019  return;
1020  case DOTTED:
1021  case DASHED: {
1022  if (width <= 0) {
1023  break;
1024  }
1025 
1026  //Figure out on/off spacing
1027  int onLen = width;
1028  int offLen = width;
1029 
1030  if (style == DASHED) {
1031  if (width == 1) {
1032  onLen = 3;
1033  offLen = 3;
1034  } else {
1035  onLen = width * 3;
1036  offLen = width;
1037  }
1038  }
1039 
1040  // Compute the offset for the dash pattern, taking the direction of
1041  // the line into account. (The borders are drawn counter-clockwise)
1042  QPoint offset(0, 0);
1043  if (nextDashOffset) {
1044  switch (s) {
1045  // The left border is drawn top to bottom
1046  case BSLeft:
1047  offset.ry() = -qRound(*nextDashOffset);
1048  *nextDashOffset += (y2 - y1);
1049  break;
1050 
1051  // The bottom border is drawn left to right
1052  case BSBottom:
1053  offset.rx() = -qRound(*nextDashOffset);
1054  *nextDashOffset += (x2 - x1);
1055  break;
1056 
1057  // The top border is drawn right to left
1058  case BSTop:
1059  offset.rx() = (x2 - x1) + offLen + qRound(*nextDashOffset);
1060  *nextDashOffset += (x2 - x1);
1061  break;
1062 
1063  // The right border is drawn bottom to top
1064  case BSRight:
1065  offset.ry() = (y2 - y1) + offLen + qRound(*nextDashOffset);
1066  *nextDashOffset += (y2 - y1);
1067  break;
1068  }
1069 
1070  offset.rx() = offset.x() % (onLen + offLen);
1071  offset.ry() = offset.y() % (onLen + offLen);
1072  }
1073 
1074  if ((onLen + offLen) <= 32 && width < 0x7fff) {
1075  if (!s_dashedLineCache) {
1076  s_dashedLineCache = new QCache<quint64, QPixmap>(30);
1077  }
1078 
1079  bool horizontal = (s == BSBottom || s == BSTop);
1080  quint64 key = int(horizontal) << 31 | (onLen & 0xff) << 23 | (offLen & 0xff) << 15 | (width & 0x7fff);
1081  key = key << 32 | c.rgba();
1082 
1083  QPixmap *tilePtr = s_dashedLineCache->object(key);
1084  QPixmap tile;
1085  if (!tilePtr) {
1086  QPainterPath path;
1087  int size = (onLen + offLen) * (64 / (onLen + offLen));
1088  if (horizontal) {
1089  tilePtr = new QPixmap(size, width);
1090  tilePtr->fill(Qt::transparent);
1091  for (int x = 0; x < tilePtr->width(); x += onLen + offLen) {
1092  path.addRect(x, 0, onLen, tilePtr->height());
1093  }
1094  } else { //Vertical
1095  tilePtr = new QPixmap(width, size);
1096  tilePtr->fill(Qt::transparent);
1097  for (int y = 0; y < tilePtr->height(); y += onLen + offLen) {
1098  path.addRect(0, y, tilePtr->width(), onLen);
1099  }
1100  }
1101  QPainter p2(tilePtr);
1102  p2.fillPath(path, c);
1103  p2.end();
1104  tile = tilePtr->copy();
1105  s_dashedLineCache->insert(key, tilePtr);
1106  }
1107  else {
1108  tile = *tilePtr;
1109  }
1110 
1111  QRect r = QRect(x1, y1, x2 - x1, y2 - y1);
1112  if (p->hasClipping()) {
1113  r &= p->clipRegion().boundingRect();
1114  }
1115 
1116  // Make sure we're drawing the pattern in the correct phase
1117  if (horizontal && r.left() > x1) {
1118  offset.rx() += (x1 - r.left());
1119  } else if (!horizontal && r.top() > y1) {
1120  offset.ry() += (y1 - r.top());
1121  }
1122 
1123  p->drawTiledPixmap(r, tile, -offset);
1124  } else {
1125  const QRect bounding(x1, y1, x2 - x1, y2 - y1);
1126  QPainterPath path;
1127  if (s == BSBottom || s == BSTop) { //Horizontal
1128  if (offset.x() > 0) {
1129  offset.rx() -= onLen + offLen;
1130  }
1131  for (int x = x1 + offset.x(); x < x2; x += onLen + offLen) {
1132  const QRect r(x, y1, qMin(onLen, (x2 - x)), width);
1133  path.addRect(r & bounding);
1134  }
1135  } else { //Vertical
1136  if (offset.y() > 0) {
1137  offset.ry() -= onLen + offLen;
1138  }
1139  for (int y = y1 + offset.y(); y < y2; y += onLen + offLen) {
1140  const QRect r(x1, y, width, qMin(onLen, (y2 - y)));
1141  path.addRect(r & bounding);
1142  }
1143  }
1144 
1145  p->fillPath(path, c);
1146  }
1147  break;
1148  }
1149  case DOUBLE: {
1150  int third = (width + 1) / 3;
1151 
1152  if (adjbw1 == 0 && adjbw2 == 0) {
1153  p->setPen(Qt::NoPen);
1154  p->setBrush(c);
1155  switch (s) {
1156  case BSTop:
1157  case BSBottom:
1158  p->drawRect(x1, y1, x2 - x1, third);
1159  p->drawRect(x1, y2 - third, x2 - x1, third);
1160  break;
1161  case BSLeft:
1162  p->drawRect(x1, y1, third, y2 - y1);
1163  p->drawRect(x2 - third, y1, third, y2 - y1);
1164  break;
1165  case BSRight:
1166  p->drawRect(x1, y1, third, y2 - y1);
1167  p->drawRect(x2 - third, y1, third, y2 - y1);
1168  break;
1169  }
1170  } else {
1171  int adjbw1bigthird;
1172  if (adjbw1 > 0) {
1173  adjbw1bigthird = adjbw1 + 1;
1174  } else {
1175  adjbw1bigthird = adjbw1 - 1;
1176  }
1177  adjbw1bigthird /= 3;
1178 
1179  int adjbw2bigthird;
1180  if (adjbw2 > 0) {
1181  adjbw2bigthird = adjbw2 + 1;
1182  } else {
1183  adjbw2bigthird = adjbw2 - 1;
1184  }
1185  adjbw2bigthird /= 3;
1186 
1187  switch (s) {
1188  case BSTop:
1189  drawBorder(p, x1 + qMax((-adjbw1 * 2 + 1) / 3, 0), y1, x2 - qMax((-adjbw2 * 2 + 1) / 3, 0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1190  drawBorder(p, x1 + qMax((adjbw1 * 2 + 1) / 3, 0), y2 - third, x2 - qMax((adjbw2 * 2 + 1) / 3, 0), y2, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1191  break;
1192  case BSLeft:
1193  drawBorder(p, x1, y1 + qMax((-adjbw1 * 2 + 1) / 3, 0), x1 + third, y2 - qMax((-adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1194  drawBorder(p, x2 - third, y1 + qMax((adjbw1 * 2 + 1) / 3, 0), x2, y2 - qMax((adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1195  break;
1196  case BSBottom:
1197  drawBorder(p, x1 + qMax((adjbw1 * 2 + 1) / 3, 0), y1, x2 - qMax((adjbw2 * 2 + 1) / 3, 0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1198  drawBorder(p, x1 + qMax((-adjbw1 * 2 + 1) / 3, 0), y2 - third, x2 - qMax((-adjbw2 * 2 + 1) / 3, 0), y2, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1199  break;
1200  case BSRight:
1201  drawBorder(p, x1, y1 + qMax((adjbw1 * 2 + 1) / 3, 0), x1 + third, y2 - qMax((adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1202  drawBorder(p, x2 - third, y1 + qMax((-adjbw1 * 2 + 1) / 3, 0), x2, y2 - qMax((-adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1203  break;
1204  default:
1205  break;
1206  }
1207  }
1208  break;
1209  }
1210  case RIDGE:
1211  case GROOVE: {
1212  EBorderStyle s1;
1213  EBorderStyle s2;
1214  if (style == GROOVE) {
1215  s1 = INSET;
1216  s2 = OUTSET;
1217  } else {
1218  s1 = OUTSET;
1219  s2 = INSET;
1220  }
1221 
1222  int adjbw1bighalf;
1223  int adjbw2bighalf;
1224  if (adjbw1 > 0) {
1225  adjbw1bighalf = adjbw1 + 1;
1226  } else {
1227  adjbw1bighalf = adjbw1 - 1;
1228  }
1229  adjbw1bighalf /= 2;
1230 
1231  if (adjbw2 > 0) {
1232  adjbw2bighalf = adjbw2 + 1;
1233  } else {
1234  adjbw2bighalf = adjbw2 - 1;
1235  }
1236  adjbw2bighalf /= 2;
1237 
1238  switch (s) {
1239  case BSTop:
1240  drawBorder(p, x1 + qMax(-adjbw1, 0) / 2, y1, x2 - qMax(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1241  drawBorder(p, x1 + qMax(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - qMax(adjbw2 + 1, 0) / 2, y2, s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
1242  break;
1243  case BSLeft:
1244  drawBorder(p, x1, y1 + qMax(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - qMax(-adjbw2, 0) / 2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1245  drawBorder(p, (x1 + x2 + 1) / 2, y1 + qMax(adjbw1 + 1, 0) / 2, x2, y2 - qMax(adjbw2 + 1, 0) / 2, s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
1246  break;
1247  case BSBottom:
1248  drawBorder(p, x1 + qMax(adjbw1, 0) / 2, y1, x2 - qMax(adjbw2, 0) / 2, (y1 + y2 + 1) / 2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1249  drawBorder(p, x1 + qMax(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - qMax(-adjbw2 + 1, 0) / 2, y2, s, c, textcolor, s1, adjbw1 / 2, adjbw2 / 2);
1250  break;
1251  case BSRight:
1252  drawBorder(p, x1, y1 + qMax(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - qMax(adjbw2, 0) / 2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1253  drawBorder(p, (x1 + x2 + 1) / 2, y1 + qMax(-adjbw1 + 1, 0) / 2, x2, y2 - qMax(-adjbw2 + 1, 0) / 2, s, c, textcolor, s1, adjbw1 / 2, adjbw2 / 2);
1254  break;
1255  }
1256  break;
1257  }
1258  case INSET:
1259  case OUTSET:
1260  calc3DColor(c, (style == OUTSET && (s == BSBottom || s == BSRight)) ||
1261  (style == INSET && (s == BSTop || s == BSLeft)));
1262  /* nobreak; */
1263  case SOLID:
1264  p->setPen(Qt::NoPen);
1265  p->setBrush(c);
1266  Q_ASSERT(x2 >= x1);
1267  Q_ASSERT(y2 >= y1);
1268  if (adjbw1 == 0 && adjbw2 == 0) {
1269  p->drawRect(x1, y1, x2 - x1, y2 - y1);
1270  return;
1271  }
1272  QPolygon quad(4);
1273  switch (s) {
1274  case BSTop:
1275  quad.setPoints(4,
1276  x1 + qMax(-adjbw1, 0), y1,
1277  x1 + qMax(adjbw1, 0), y2,
1278  x2 - qMax(adjbw2, 0), y2,
1279  x2 - qMax(-adjbw2, 0), y1);
1280  break;
1281  case BSBottom:
1282  quad.setPoints(4,
1283  x1 + qMax(adjbw1, 0), y1,
1284  x1 + qMax(-adjbw1, 0), y2,
1285  x2 - qMax(-adjbw2, 0), y2,
1286  x2 - qMax(adjbw2, 0), y1);
1287  break;
1288  case BSLeft:
1289  quad.setPoints(4,
1290  x1, y1 + qMax(-adjbw1, 0),
1291  x1, y2 - qMax(-adjbw2, 0),
1292  x2, y2 - qMax(adjbw2, 0),
1293  x2, y1 + qMax(adjbw1, 0));
1294  break;
1295  case BSRight:
1296  quad.setPoints(4,
1297  x1, y1 + qMax(adjbw1, 0),
1298  x1, y2 - qMax(adjbw2, 0),
1299  x2, y2 - qMax(-adjbw2, 0),
1300  x2, y1 + qMax(-adjbw1, 0));
1301  break;
1302  }
1303  p->drawConvexPolygon(quad);
1304  break;
1305  }
1306 
1307  if (invalidisInvert && p->compositionMode() == QPainter::CompositionMode_Difference) {
1309  }
1310 }
1311 
1312 void RenderObject::calcBorderRadii(QPoint &topLeftRadii, QPoint &topRightRadii, QPoint &bottomLeftRadii, QPoint &bottomRightRadii, int w, int h) const
1313 {
1314  // CSS Backgrounds and Borders Module Level 3 (https://www.w3.org/TR/2014/CR-css3-background-20140909/), chapter 5.5:
1315  // "Corner curves must not overlap: When the sum of any two adjacent border radii exceeds the size of the border box,
1316  // UAs must proportionally reduce the used values of all border radii until none of them overlap.
1317  // The algorithm for reducing radii is as follows: ..."
1318 
1319  const RenderStyle *s = style();
1320  if (!s->hasBorderRadius()) {
1321  return;
1322  }
1323 
1324  // Border radii Length is Fixed|Percent
1325  topLeftRadii.rx() = s->borderTopLeftRadius().horizontal.minWidth(w);
1326  topLeftRadii.ry() = s->borderTopLeftRadius().vertical.minWidth(h);
1327  topRightRadii.rx() = s->borderTopRightRadius().horizontal.minWidth(w);
1328  topRightRadii.ry() = s->borderTopRightRadius().vertical.minWidth(h);
1329  bottomLeftRadii.rx() = s->borderBottomLeftRadius().horizontal.minWidth(w);
1330  bottomLeftRadii.ry() = s->borderBottomLeftRadius().vertical.minWidth(h);
1331  bottomRightRadii.rx() = s->borderBottomRightRadius().horizontal.minWidth(w);
1332  bottomRightRadii.ry() = s->borderBottomRightRadius().vertical.minWidth(h);
1333 
1334  // Adjust the border radii so they don't overlap when taking the size of the box into account.
1335 
1336  const int horS = qMax(topLeftRadii.x() + topRightRadii.x(), bottomLeftRadii.x() + bottomRightRadii.x());
1337  const int verS = qMax(topLeftRadii.y() + bottomLeftRadii.y(), topRightRadii.y() + bottomRightRadii.y());
1338 
1339  qreal f = 1.0;
1340  if (horS > 0) {
1341  f = qMin(f, w / qreal(horS));
1342  }
1343  if (verS > 0) {
1344  f = qMin(f, h / qreal(verS));
1345  }
1346 
1347  if (f < 1.0) {
1348  topLeftRadii *= f;
1349  topRightRadii *= f;
1350  bottomLeftRadii *= f;
1351  bottomRightRadii *= f;
1352  }
1353 }
1354 
1355 static QImage blendCornerImages(const QImage &image1, const QImage &image2)
1356 {
1358  QImage composite = image1;
1359  QImage temp = image2;
1360 
1361  // Construct the mask image
1362  QConicalGradient gradient(mask.width() / 2, mask.height() / 2, 0);
1363  gradient.setColorAt(0.00, Qt::transparent);
1364  gradient.setColorAt(0.25, Qt::black);
1365  gradient.setColorAt(0.50, Qt::black);
1366  gradient.setColorAt(0.75, Qt::transparent);
1367  gradient.setColorAt(1.00, Qt::transparent);
1368 
1369  QBrush gradientBrush = gradient;
1370 
1371  if (mask.width() != mask.height()) {
1372  int min = qMin(mask.width(), mask.height());
1373  QTransform xform;
1374  xform.translate(mask.width() / 2, mask.height() / 2);
1375  xform.scale(min / mask.width(), min / mask.height());
1376  gradientBrush.setTransform(xform);
1377  }
1378 
1379  QPainter p;
1380  p.begin(&mask);
1382  p.fillRect(mask.rect(), gradientBrush);
1383  p.end();
1384 
1385  p.begin(&temp);
1387  p.drawImage(0, 0, mask);
1388  p.end();
1389 
1390  p.begin(&composite);
1392  p.drawImage(0, 0, mask);
1394  p.drawImage(0, 0, temp);
1395  p.end();
1396 
1397  return composite;
1398 }
1399 
1400 static QBrush cornerGradient(int cx, int cy, const QPoint &radius, int angleStart, int angleSpan,
1401  const QColor &startColor, const QColor &finalColor)
1402 {
1403  QConicalGradient g(0, 0, angleStart);
1404  g.setColorAt(0, startColor);
1405  g.setColorAt(angleSpan / 360.0, finalColor);
1406 
1407  QBrush brush(g);
1408 
1409  QTransform xform;
1410  xform.translate(cx, cy);
1411 
1412  if (radius.x() < radius.y()) {
1413  xform.scale(radius.x() / radius.y(), 1);
1414  } else if (radius.y() < radius.x()) {
1415  xform.scale(1, radius.y() / radius.x());
1416  }
1417 
1418  brush.setTransform(xform);
1419  return brush;
1420 }
1421 
1422 void RenderObject::drawBorderArc(QPainter *p, int x, int y, float horThickness, float vertThickness,
1423  const QPoint &radius, int angleStart, int angleSpan, const QBrush &brush,
1424  const QColor &textColor, EBorderStyle style, qreal *nextDashOffset) const
1425 {
1426  QColor c = brush.color();
1427  if (!c.isValid()) {
1428  if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE) {
1429  c = Qt::white;
1430  } else {
1431  c = textColor;
1432  }
1433  }
1434 
1435  QColor light = c;
1436  QColor dark = c;
1437  calc3DColor(light, false);
1438  calc3DColor(dark, true);
1439 
1440  if (style == DOUBLE && horThickness < 3 && vertThickness < 3) {
1441  style = SOLID;
1442  }
1443 
1444  if (nextDashOffset && style != DOTTED && style != DASHED) {
1445  *nextDashOffset = 0;
1446  }
1447 
1448  p->save();
1450 
1451  switch (style) {
1452  case BNATIVE:
1453  case BNONE:
1454  case BHIDDEN: {
1455  // Should not happen
1456  break;
1457  }
1458 
1459  case SOLID: {
1460  const QRect outerRect = QRect(x - radius.x(), y - radius.y(), radius.x() * 2, radius.y() * 2);
1461  const QRect innerRect = outerRect.adjusted(horThickness, vertThickness, -horThickness, -vertThickness);
1462  QPainterPath path;
1463  path.arcMoveTo(outerRect, angleStart);
1464  path.arcTo(outerRect, angleStart, angleSpan);
1465  if (innerRect.isValid()) {
1466  path.arcTo(innerRect, angleStart + angleSpan, -angleSpan);
1467  } else {
1468  path.lineTo(x, y);
1469  }
1470  path.closeSubpath();
1471  p->fillPath(path, brush);
1472  break;
1473  }
1474 
1475  case DOUBLE: {
1476  const qreal hw = (horThickness + 1) / 3;
1477  const qreal vw = (vertThickness + 1) / 3;
1478 
1479  QPoint br(radius.x() - hw * 2 + 1, radius.y() - vw * 2 + 1);
1480 
1481  drawBorderArc(p, x, y, hw, vw, radius, angleStart, angleSpan, brush, textColor, SOLID);
1482  drawBorderArc(p, x, y, hw, vw, br, angleStart, angleSpan, brush, textColor, SOLID);
1483  break;
1484  }
1485 
1486  case INSET:
1487  case OUTSET: {
1488  QImage image1(radius.x() * 2, radius.y() * 2, QImage::Format_ARGB32_Premultiplied);
1489  image1.fill(0);
1490 
1491  QImage image2 = image1;
1492 
1493  const QColor c1 = style == OUTSET ? dark : light;
1494  const QColor c2 = style == OUTSET ? light : dark;
1495 
1496  QPainter p2;
1497  p2.begin(&image1);
1498  drawBorderArc(&p2, radius.x(), radius.y(), horThickness, vertThickness,
1499  radius, angleStart, angleSpan, c1, textColor, SOLID);
1500  p2.end();
1501 
1502  p2.begin(&image2);
1503  drawBorderArc(&p2, radius.x(), radius.y(), horThickness, vertThickness,
1504  radius, angleStart, angleSpan, c2, textColor, SOLID);
1505  p2.end();
1506 
1507  p->drawImage(x - radius.x(), y - radius.y(), blendCornerImages(image1, image2));
1508  break;
1509  }
1510 
1511  case RIDGE:
1512  case GROOVE: {
1513  QImage image1(radius.x() * 2, radius.y() * 2, QImage::Format_ARGB32_Premultiplied);
1514  image1.fill(0);
1515 
1516  QImage image2 = image1;
1517 
1518  const QColor c1 = style == RIDGE ? dark : light;
1519  const QColor c2 = style == RIDGE ? light : dark;
1520 
1521  const qreal hw = horThickness / 2;
1522  const qreal vw = vertThickness / 2;
1523  int cx = radius.x();
1524  int cy = radius.y();
1525 
1526  QPoint innerRadius(radius.x() - hw, radius.y() - vw);
1527 
1528  QPainter p2;
1529  p2.begin(&image1);
1530  drawBorderArc(&p2, cx, cy, hw, vw, radius, angleStart, angleSpan, c1, textColor, SOLID);
1531  drawBorderArc(&p2, cx, cy, hw, vw, innerRadius, angleStart, angleSpan, c2, textColor, SOLID);
1532  p2.end();
1533 
1534  p2.begin(&image2);
1535  drawBorderArc(&p2, cx, cy, hw, vw, radius, angleStart, angleSpan, c2, textColor, SOLID);
1536  drawBorderArc(&p2, cx, cy, hw, vw, innerRadius, angleStart, angleSpan, c1, textColor, SOLID);
1537  p2.end();
1538 
1539  p->drawImage(x - radius.x(), y - radius.y(), blendCornerImages(image1, image2));
1540  break;
1541  }
1542 
1543  case DOTTED:
1544  case DASHED: {
1545  const QRectF rect = QRectF(x - radius.x(), y - radius.y(), radius.x() * 2, radius.y() * 2);
1546  int width;
1547 
1548  // Figure out which border we're starting from
1549  angleStart = angleStart % 360;
1550  if (angleStart < 0) {
1551  angleStart += 360;
1552  }
1553 
1554  if ((angleStart > 45 && angleStart <= 135) || (angleStart > 225 && angleStart <= 315)) {
1555  width = vertThickness;
1556  } else {
1557  width = horThickness;
1558  }
1559 
1560  int onLen = width;
1561  int offLen = width;
1562 
1563  if (style == DASHED) {
1564  if (width == 1) {
1565  onLen = 3;
1566  offLen = 3;
1567  } else {
1568  onLen = width * 3;
1569  offLen = width;
1570  }
1571  }
1572 
1573  BorderArcStroker stroker;
1574  stroker.setArc(rect, angleStart, angleSpan);
1575  stroker.setPenWidth(horThickness, vertThickness);
1576  stroker.setDashPattern(onLen, offLen);
1577  stroker.setDashOffset(*nextDashOffset);
1578 
1579  const QPainterPath path = stroker.createStroke(nextDashOffset);
1580  p->fillPath(path, brush);
1581  }
1582  }
1583 
1584  p->restore();
1585 }
1586 
1587 void RenderObject::paintBorder(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle *style, bool begin, bool end)
1588 {
1589  const QColor &tc = style->borderTopColor();
1590  const QColor &bc = style->borderBottomColor();
1591  const QColor &lc = style->borderLeftColor();
1592  const QColor &rc = style->borderRightColor();
1593 
1594  bool tt = style->borderTopIsTransparent();
1595  bool bt = style->borderBottomIsTransparent();
1596  bool rt = style->borderRightIsTransparent();
1597  bool lt = style->borderLeftIsTransparent();
1598 
1599  EBorderStyle ts = style->borderTopStyle();
1600  EBorderStyle bs = style->borderBottomStyle();
1601  EBorderStyle ls = style->borderLeftStyle();
1602  EBorderStyle rs = style->borderRightStyle();
1603 
1604  bool render_t = ts > BHIDDEN && !tt;
1605  bool render_l = ls > BHIDDEN && begin && !lt;
1606  bool render_r = rs > BHIDDEN && end && !rt;
1607  bool render_b = bs > BHIDDEN && !bt;
1608 
1609  QPoint topLeftRadii, topRightRadii, bottomLeftRadii, bottomRightRadii;
1610  calcBorderRadii(topLeftRadii, topRightRadii, bottomLeftRadii, bottomRightRadii, w, h);
1611 
1612  bool upperLeftBorderStylesMatch = render_l && (ts == ls) && (tc == lc);
1613  bool upperRightBorderStylesMatch = render_r && (ts == rs) && (tc == rc);
1614  bool lowerLeftBorderStylesMatch = render_l && (bs == ls) && (bc == lc);
1615  bool lowerRightBorderStylesMatch = render_r && (bs == rs) && (bc == rc);
1616 
1617  // We do a gradient transition for dotted, dashed, solid and double lines
1618  // when the styles match but the colors differ.
1619  bool upperLeftGradient = render_t && render_l && ts == ls && tc != lc && ts > OUTSET;
1620  bool upperRightGradient = render_t && render_r && ts == rs && tc != rc && ts > OUTSET;
1621  bool lowerLeftGradient = render_b && render_l && bs == ls && bc != lc && bs > OUTSET;
1622  bool lowerRightGradient = render_b && render_r && bs == rs && bc != rc && bs > OUTSET;
1623 
1624  qreal nextDashOffset = 0;
1625 
1626  // Draw the borders counter-clockwise starting with the upper right corner
1627  if (render_t) {
1628  bool ignore_left = (topLeftRadii.x() > 0) ||
1629  ((tc == lc) && (tt == lt) &&
1630  (ts >= OUTSET) &&
1631  (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1632 
1633  bool ignore_right = (topRightRadii.x() > 0) ||
1634  ((tc == rc) && (tt == rt) &&
1635  (ts >= OUTSET) &&
1636  (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1637 
1638  int x = _tx + topLeftRadii.x();
1639  int x2 = _tx + w - topRightRadii.x();
1640 
1641  if (!topRightRadii.isNull()) {
1642  int x = _tx + w - topRightRadii.x();
1643  int y = _ty + topRightRadii.y();
1644  int startAngle, span;
1645 
1646  if (upperRightBorderStylesMatch || upperRightGradient) {
1647  startAngle = 0;
1648  span = 90;
1649  } else {
1650  startAngle = 45;
1651  span = 45;
1652  }
1653 
1654  const QBrush brush = upperRightGradient ?
1655  cornerGradient(x, y, topRightRadii, startAngle, span, rc, tc) : tc;
1656 
1657  // Draw the upper right arc
1658  drawBorderArc(p, x, y, style->borderRightWidth(), style->borderTopWidth(),
1659  topRightRadii, startAngle, span, brush, style->color(), ts, &nextDashOffset);
1660  }
1661 
1662  drawBorder(p, x, _ty, x2, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
1663  ignore_left ? 0 : style->borderLeftWidth(),
1664  ignore_right ? 0 : style->borderRightWidth(), false, &nextDashOffset);
1665 
1666  if (!topLeftRadii.isNull()) {
1667  int x = _tx + topLeftRadii.x();
1668  int y = _ty + topLeftRadii.y();
1669  int startAngle = 90;
1670  int span = (upperLeftBorderStylesMatch || upperLeftGradient) ? 90 : 45;
1671  const QBrush brush = upperLeftGradient ?
1672  cornerGradient(x, y, topLeftRadii, startAngle, span, tc, lc) : tc;
1673 
1674  // Draw the upper left arc
1675  drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderTopWidth(),
1676  topLeftRadii, startAngle, span, brush, style->color(), ts, &nextDashOffset);
1677  } else if (ls == DASHED || ls == DOTTED) {
1678  nextDashOffset = 0; // Reset the offset to avoid partially overlapping dashes
1679  }
1680  }
1681 
1682  if (render_l) {
1683  bool ignore_top = (topLeftRadii.y() > 0) ||
1684  ((tc == lc) && (tt == lt) &&
1685  (ls >= OUTSET) &&
1686  (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1687 
1688  bool ignore_bottom = (bottomLeftRadii.y() > 0) ||
1689  ((bc == lc) && (bt == lt) &&
1690  (ls >= OUTSET) &&
1691  (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1692 
1693  int y = _ty + topLeftRadii.y();
1694  int y2 = _ty + h - bottomLeftRadii.y();
1695 
1696  if (!upperLeftBorderStylesMatch && !upperLeftGradient && !topLeftRadii.isNull()) {
1697  int x = _tx + topLeftRadii.x();
1698  int y = _ty + topLeftRadii.y();
1699  int startAngle = 135;
1700  int span = 45;
1701 
1702  // Draw the upper left arc
1703  drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderTopWidth(),
1704  topLeftRadii, startAngle, span, lc, style->color(), ls, &nextDashOffset);
1705  }
1706 
1707  drawBorder(p, _tx, y, _tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
1708  ignore_top ? 0 : style->borderTopWidth(),
1709  ignore_bottom ? 0 : style->borderBottomWidth(), false, &nextDashOffset);
1710 
1711  if (!lowerLeftBorderStylesMatch && !lowerLeftGradient && !bottomLeftRadii.isNull()) {
1712  int x = _tx + bottomLeftRadii.x();
1713  int y = _ty + h - bottomLeftRadii.y();
1714  int startAngle = 180;
1715  int span = 45;
1716 
1717  // Draw the bottom left arc
1718  drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderBottomWidth(),
1719  bottomLeftRadii, startAngle, span, lc, style->color(), ls, &nextDashOffset);
1720  }
1721 
1722  // Reset the offset to avoid partially overlapping dashes
1723  if (bottomLeftRadii.isNull() && (bs == DASHED || bs == DOTTED)) {
1724  nextDashOffset = 0;
1725  }
1726  }
1727 
1728  if (render_b) {
1729  bool ignore_left = (bottomLeftRadii.x() > 0) ||
1730  ((bc == lc) && (bt == lt) &&
1731  (bs >= OUTSET) &&
1732  (ls == DOTTED || ls == DASHED || ls == SOLID || ls == INSET));
1733 
1734  bool ignore_right = (bottomRightRadii.x() > 0) ||
1735  ((bc == rc) && (bt == rt) &&
1736  (bs >= OUTSET) &&
1737  (rs == DOTTED || rs == DASHED || rs == SOLID || rs == OUTSET));
1738 
1739  int x = _tx + bottomLeftRadii.x();
1740  int x2 = _tx + w - bottomRightRadii.x();
1741 
1742  if (!bottomLeftRadii.isNull()) {
1743  int x = _tx + bottomLeftRadii.x();
1744  int y = _ty + h - bottomLeftRadii.y();
1745  int startAngle, span;
1746 
1747  if (lowerLeftBorderStylesMatch || lowerLeftGradient) {
1748  startAngle = 180;
1749  span = 90;
1750  } else {
1751  startAngle = 225;
1752  span = 45;
1753  }
1754 
1755  const QBrush brush = lowerLeftGradient ?
1756  cornerGradient(x, y, bottomLeftRadii, startAngle, span, lc, bc) : bc;
1757 
1758  // Draw the bottom left arc
1759  drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderBottomWidth(),
1760  bottomLeftRadii, startAngle, span, brush, style->color(), bs, &nextDashOffset);
1761  }
1762 
1763  drawBorder(p, x, _ty + h - style->borderBottomWidth(), x2, _ty + h, BSBottom, bc, style->color(), bs,
1764  ignore_left ? 0 : style->borderLeftWidth(),
1765  ignore_right ? 0 : style->borderRightWidth(), false, &nextDashOffset);
1766 
1767  if (!bottomRightRadii.isNull()) {
1768  int x = _tx + w - bottomRightRadii.x();
1769  int y = _ty + h - bottomRightRadii.y();
1770  int startAngle = 270;
1771  int span = (lowerRightBorderStylesMatch || lowerRightGradient) ? 90 : 45;
1772  const QBrush brush = lowerRightGradient ?
1773  cornerGradient(x, y, bottomRightRadii, startAngle, span, bc, rc) : bc;
1774 
1775  // Draw the bottom right arc
1776  drawBorderArc(p, x, y, style->borderRightWidth(), style->borderBottomWidth(),
1777  bottomRightRadii, startAngle, span, brush, style->color(), bs, &nextDashOffset);
1778  } else if (rs == DASHED || rs == DOTTED) {
1779  nextDashOffset = 0; // Reset the offset to avoid partially overlapping dashes
1780  }
1781  }
1782 
1783  if (render_r) {
1784  bool ignore_top = (topRightRadii.y() > 0) ||
1785  ((tc == rc) && (tt == rt) &&
1786  (rs >= DOTTED || rs == INSET) &&
1787  (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1788 
1789  bool ignore_bottom = (bottomRightRadii.y() > 0) ||
1790  ((bc == rc) && (bt == rt) &&
1791  (rs >= DOTTED || rs == INSET) &&
1792  (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1793 
1794  int y = _ty + topRightRadii.y();
1795  int y2 = _ty + h - bottomRightRadii.y();
1796 
1797  if (!lowerRightBorderStylesMatch && !lowerRightGradient && !bottomRightRadii.isNull()) {
1798  int x = _tx + w - bottomRightRadii.x();
1799  int y = _ty + h - bottomRightRadii.y();
1800  int startAngle = 315;
1801  int span = 45;
1802 
1803  // Draw the bottom right arc
1804  drawBorderArc(p, x, y, style->borderRightWidth(), style->borderBottomWidth(),
1805  bottomRightRadii, startAngle, span, rc, style->color(), rs, &nextDashOffset);
1806  }
1807 
1808  drawBorder(p, _tx + w - style->borderRightWidth(), y, _tx + w, y2, BSRight, rc, style->color(), rs,
1809  ignore_top ? 0 : style->borderTopWidth(),
1810  ignore_bottom ? 0 : style->borderBottomWidth(), false, &nextDashOffset);
1811 
1812  if (!upperRightBorderStylesMatch && !upperRightGradient && !topRightRadii.isNull()) {
1813  int x = _tx + w - topRightRadii.x();
1814  int y = _ty + topRightRadii.y();
1815  int startAngle = 0;
1816  int span = 45;
1817 
1818  // Draw the upper right arc
1819  drawBorderArc(p, x, y, style->borderRightWidth(), style->borderTopWidth(),
1820  topRightRadii, startAngle, span, rc, style->color(), rs, &nextDashOffset);
1821  }
1822  }
1823 }
1824 
1825 void RenderObject::paintOutline(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle *style)
1826 {
1827  int ow = style->outlineWidth();
1828  if (!ow) {
1829  return;
1830  }
1831 
1832  const QColor &oc = style->outlineColor();
1833  EBorderStyle os = style->outlineStyle();
1834  int offset = style->outlineOffset();
1835 
1836 #ifdef APPLE_CHANGES
1837  if (style->outlineStyleIsAuto()) {
1838  p->initFocusRing(ow, offset, oc);
1839  addFocusRingRects(p, _tx, _ty);
1840  p->drawFocusRing();
1841  p->clearFocusRing();
1842  return;
1843  }
1844 #endif
1845 
1846  _tx -= offset;
1847  _ty -= offset;
1848  w += 2 * offset;
1849  h += 2 * offset;
1850 
1851  drawBorder(p, _tx - ow, _ty - ow, _tx, _ty + h + ow, BSLeft,
1852  QColor(oc), style->color(),
1853  os, ow, ow, true);
1854 
1855  drawBorder(p, _tx - ow, _ty - ow, _tx + w + ow, _ty, BSTop,
1856  QColor(oc), style->color(),
1857  os, ow, ow, true);
1858 
1859  drawBorder(p, _tx + w, _ty - ow, _tx + w + ow, _ty + h + ow, BSRight,
1860  QColor(oc), style->color(),
1861  os, ow, ow, true);
1862 
1863  drawBorder(p, _tx - ow, _ty + h, _tx + w + ow, _ty + h + ow, BSBottom,
1864  QColor(oc), style->color(),
1865  os, ow, ow, true);
1866 
1867 }
1868 
1869 void RenderObject::paint(PaintInfo &, int /*tx*/, int /*ty*/)
1870 {
1871 }
1872 
1873 void RenderObject::repaintRectangle(int x, int y, int w, int h, Priority p, bool f)
1874 {
1875  if (parent()) {
1876  parent()->repaintRectangle(x, y, w, h, p, f);
1877  }
1878 }
1879 
1880 #ifdef ENABLE_DUMP
1881 
1882 QString RenderObject::information() const
1883 {
1884  QString str;
1885  int x; int y;
1886  absolutePosition(x, y);
1887  x += inlineXPos();
1888  y += inlineYPos();
1890  ts << renderName()
1891  << "(" << (style() ? style()->refCount() : 0) << ")"
1892  << ": " << (void *)this << " ";
1893  ts << "{" << x << " " << y << "} ";
1894  if (isInline()) {
1895  ts << "il ";
1896  }
1897  if (childrenInline()) {
1898  ts << "ci ";
1899  }
1900  if (isFloating()) {
1901  ts << "fl ";
1902  }
1903  if (isAnonymous()) {
1904  ts << "an ";
1905  }
1906  if (isRelPositioned()) {
1907  ts << "rp ";
1908  }
1909  if (isPositioned()) {
1910  ts << "ps ";
1911  }
1912  if (isReplaced()) {
1913  ts << "rp ";
1914  }
1915  if (needsLayout()) {
1916  ts << "nl ";
1917  }
1918  if (minMaxKnown()) {
1919  ts << "mmk ";
1920  }
1921  if (m_recalcMinMax) {
1922  ts << "rmm ";
1923  }
1924  if (mouseInside()) {
1925  ts << "mi ";
1926  }
1927  if (style() && style()->zIndex()) {
1928  ts << "zI: " << style()->zIndex();
1929  }
1930  if (style() && style()->hasAutoZIndex()) {
1931  ts << "zI: auto ";
1932  }
1933  if (element()) {
1934  if (element()->active()) {
1935  ts << "act ";
1936  }
1937  if (element()->hasAnchor()) {
1938  ts << "anchor ";
1939  }
1940  if (element()->focused()) {
1941  ts << "focus ";
1942  }
1943  ts << " <" << LocalName::fromId(localNamePart(element()->id())).toString().string() << ">";
1944 
1945  } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO) {
1946  ts << " <" << LocalName::fromId(localNamePart(node()->id())).toString().string();
1947  QString pseudo;
1948  switch (style()->styleType()) {
1949  case RenderStyle::FIRST_LETTER:
1950  pseudo = ":first-letter"; break;
1951  case RenderStyle::BEFORE:
1952  pseudo = ":before"; break;
1953  case RenderStyle::AFTER:
1954  pseudo = ":after"; break;
1955  default:
1956  pseudo = ":pseudo-element";
1957  }
1958  ts << pseudo;
1959  ts << ">";
1960  }
1961  ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")"
1962  << " [" << minWidth() << "-" << maxWidth() << "]"
1963  << " { mT: " << marginTop() << " qT: " << isTopMarginQuirk()
1964  << " mB: " << marginBottom() << " qB: " << isBottomMarginQuirk()
1965  << "}"
1966  << (isTableCell() ?
1967  (QLatin1String(" [r=") +
1968  QString::number(static_cast<const RenderTableCell *>(this)->row()) +
1969  QLatin1String(" c=") +
1970  QString::number(static_cast<const RenderTableCell *>(this)->col()) +
1971  QLatin1String(" rs=") +
1972  QString::number(static_cast<const RenderTableCell *>(this)->rowSpan()) +
1973  QLatin1String(" cs=") +
1974  QString::number(static_cast<const RenderTableCell *>(this)->colSpan()) +
1975  QLatin1String("]")) : QString());
1976  if (layer()) {
1977  ts << " layer=" << layer();
1978  }
1979  if (continuation()) {
1980  ts << " continuation=" << continuation();
1981  }
1982  if (isText()) {
1983  ts << " \"" << QString::fromRawData(static_cast<const RenderText *>(this)->text(), qMin(static_cast<const RenderText *>(this)->length(), 10u)) << "\"";
1984  }
1985  return str;
1986 }
1987 
1988 void RenderObject::printTree(int indent) const
1989 {
1990  QString ind;
1991  ind.fill(' ', indent);
1992 
1993  // qCDebug(KHTML_LOG) << (ind + information());
1994 
1995  RenderObject *child = firstChild();
1996  while (child != nullptr) {
1997  child->printTree(indent + 2);
1998  child = child->nextSibling();
1999  }
2000 }
2001 
2002 static QTextStream &operator<<(QTextStream &ts, const QRect &r)
2003 {
2004  return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
2005 }
2006 
2007 //A bit like getTagName, but handles XML, too.
2008 static QString lookupTagName(NodeImpl *node)
2009 {
2010  return LocalName::fromId(node->id()).toString().string();
2011 }
2012 
2013 void RenderObject::dump(QTextStream &ts, const QString &ind) const
2014 {
2015  if (!layer()) {
2016  ts << endl;
2017  }
2018 
2019  ts << ind << renderName();
2020 
2021  if (style() && style()->zIndex()) {
2022  ts << " zI: " << style()->zIndex();
2023  }
2024 
2025  if (element()) {
2026  QString tagName(lookupTagName(element()));
2027  if (!tagName.isEmpty()) {
2028  ts << " {" << tagName << "}";
2029  }
2030  } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO) {
2031  QString pseudo;
2032  QString tagName(lookupTagName(node()));
2033  switch (style()->styleType()) {
2034  case RenderStyle::FIRST_LETTER:
2035  pseudo = ":first-letter"; break;
2036  case RenderStyle::BEFORE:
2037  pseudo = ":before"; break;
2038  case RenderStyle::AFTER:
2039  pseudo = ":after"; break;
2040  default:
2041  pseudo = ":pseudo-element";
2042  }
2043  ts << " {" << tagName << pseudo << "}";
2044  }
2045 
2046  QRect r(xPos(), yPos(), width(), height());
2047  ts << " " << r;
2048 
2049  if (parent()) {
2050  ts << style()->createDiff(*parent()->style());
2051  }
2052 
2053  if (isAnonymous()) {
2054  ts << " anonymousBox";
2055  }
2056  if (isFloating()) {
2057  ts << " floating";
2058  }
2059  if (isPositioned()) {
2060  ts << " positioned";
2061  }
2062  if (isRelPositioned()) {
2063  ts << " relPositioned";
2064  }
2065  if (isText()) {
2066  ts << " text";
2067  }
2068  if (isInline()) {
2069  ts << " inline";
2070  }
2071  if (isReplaced()) {
2072  ts << " replaced";
2073  }
2074  if (shouldPaintBackgroundOrBorder()) {
2075  ts << " paintBackground";
2076  }
2077  if (needsLayout()) {
2078  ts << " needsLayout";
2079  }
2080  if (minMaxKnown()) {
2081  ts << " minMaxKnown";
2082  }
2083  if (hasFirstLine()) {
2084  ts << " hasFirstLine";
2085  }
2086  if (afterPageBreak()) {
2087  ts << " afterPageBreak";
2088  }
2089 }
2090 
2091 void RenderObject::printLineBoxTree() const
2092 {
2093  RenderObject *child = firstChild();
2094  for (; child; child = child->nextSibling()) {
2095  child->printLineBoxTree();
2096  }
2097  if (isRenderBlock()) {
2098  const RenderBlock *block = static_cast<const RenderBlock *>(this);
2099  RootInlineBox *rootBox = block->firstRootBox();
2100  for (; rootBox; rootBox = rootBox->nextRootBox()) {
2101  rootBox->printTree();
2102  }
2103  }
2104 }
2105 #endif
2106 
2107 bool RenderObject::shouldSelect() const
2108 {
2109 #if 0 // ### merge
2110  const RenderObject *curr = this;
2111  DOM::NodeImpl *node = 0;
2112  bool forcedOn = false;
2113 
2114  while (curr) {
2115  if (curr->style()->userSelect() == SELECT_TEXT) {
2116  forcedOn = true;
2117  }
2118  if (!forcedOn && curr->style()->userSelect() == SELECT_NONE) {
2119  return false;
2120  }
2121 
2122  if (!node) {
2123  node = curr->element();
2124  }
2125  curr = curr->parent();
2126  }
2127 
2128  // somewhere up the render tree there must be an element!
2129  assert(node);
2130 
2131  return node->dispatchHTMLEvent(DOM::EventImpl::SELECTSTART_EVENT, true, true);
2132 #else
2133  return true;
2134 #endif
2135 }
2136 
2137 void RenderObject::selectionStartEnd(int &spos, int &epos)
2138 {
2139  if (parent()) {
2140  parent()->selectionStartEnd(spos, epos);
2141  }
2142 }
2143 
2144 void RenderObject::setStyle(RenderStyle *style)
2145 {
2146  if (m_style == style) {
2147  return;
2148  }
2149 
2150  RenderStyle::Diff d = m_style ? m_style->diff(style) : RenderStyle::Layout;
2151  //qDebug("m_style: %p new style, diff=%d", m_style, d);
2152 
2153  Priority pri = NormalPriority;
2154  if (m_style) {
2155  pri = HighPriority;
2156  if (d >= RenderStyle::Visible && !isText() && m_parent &&
2157  (d == RenderStyle::Position ||
2158  m_style->outlineWidth() > style->outlineWidth() ||
2159  (!m_style->hidesOverflow() && style->hidesOverflow()) ||
2160  (m_style->hasClip() && !(m_style->clip() == style->clip())))) {
2161  // schedule a repaint with the old style
2162  if (layer() && !isInlineFlow()) {
2163  layer()->repaint(pri);
2164  } else {
2165  repaint(pri);
2166  }
2167  }
2168 
2169  if ((isFloating() && m_style->floating() != style->floating()) ||
2170  (isPositioned() && m_style->position() != style->position() &&
2171  style->position() != PABSOLUTE && style->position() != PFIXED)) {
2172  removeFromObjectLists();
2173  }
2174 
2175  if (layer()) {
2176  if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2177  m_style->zIndex() != style->zIndex() ||
2178  m_style->visibility() != style->visibility())) {
2179  layer()->stackingContext()->dirtyZOrderLists();
2180  layer()->dirtyZOrderLists();
2181  }
2182  // keep layer hierarchy visibility bits up to date if visibility changes
2183  if (m_style->visibility() != style->visibility()) {
2184  RenderLayer *l = enclosingLayer();
2185  if (style->visibility() == VISIBLE && l) {
2186  l->setHasVisibleContent(true);
2187  } else if (l && l->hasVisibleContent() &&
2188  (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) {
2189  l->dirtyVisibleContentStatus();
2190  }
2191  }
2192  }
2193 
2194  // reset style flags
2195  m_floating = false;
2196  m_positioned = false;
2197  m_relPositioned = false;
2198  m_paintBackground = false;
2199  m_hasOverflowClip = false;
2200  }
2201 
2202  // only honor z-index for non-static objects and objects with opacity
2203  if (style->position() == PSTATIC && style->opacity() == 1.0f) {
2204  style->setHasAutoZIndex();
2205  }
2206  // force establishment of a stacking context by transparent objects, as those define
2207  // the bounds of an atomically painted region.
2208  if (style->hasAutoZIndex() && (isRoot() || style->opacity() < 1.0f)) {
2209  style->setZIndex(0);
2210  }
2211 
2212  if (d > RenderStyle::Position &&
2213  (style->hasFixedBackgroundImage() != (m_style && m_style->hasFixedBackgroundImage())
2214  || (style->position() == PFIXED) != (m_style && (m_style->position() == PFIXED)))
2215  && canvas() && canvas()->view()) {
2216  // some sort of fixed object is added or removed. Let's find out more and report to the canvas,
2217  // so that it does some bookkeeping and optimizes the view's background display mode accordingly.
2218  bool fixedBG = style->hasFixedBackgroundImage();
2219  bool oldFixedBG = m_style && m_style->hasFixedBackgroundImage();
2220  bool fixedPos = (style->position() == PFIXED);
2221  bool oldFixedPos = m_style && (m_style->position() == PFIXED);
2222  if (fixedBG != oldFixedBG) {
2223  if (fixedBG) {
2224  canvas()->addStaticObject(this);
2225  } else {
2226  canvas()->removeStaticObject(this);
2227  }
2228  }
2229  if (fixedPos != oldFixedPos) {
2230  if (fixedPos) {
2231  canvas()->addStaticObject(this, true /*positioned*/);
2232  } else {
2233  canvas()->removeStaticObject(this, true);
2234  }
2235  }
2236  }
2237 
2238  RenderStyle *oldStyle = m_style;
2239  m_style = style;
2240 
2241  updateBackgroundImages(oldStyle);
2242 
2243  m_style->ref();
2244 
2245  if (oldStyle) {
2246  oldStyle->deref();
2247  }
2248 
2249  setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground());
2250 
2251  m_hasFirstLine = (style->getPseudoStyle(RenderStyle::FIRST_LINE) != nullptr);
2252  if (m_parent) {
2253  if (d == RenderStyle::Position && !attemptDirectLayerTranslation()) {
2254  d = RenderStyle::Layout;
2255  }
2256 
2257  if (d > RenderStyle::Position) {
2258  // we must perform a full layout
2259  if (!isText() && d == RenderStyle::CbLayout) {
2260  dirtyFormattingContext(true);
2261  }
2262  setNeedsLayoutAndMinMaxRecalc();
2263  } else if (!isText() && d >= RenderStyle::Visible) {
2264  // a repaint is enough
2265  if (layer()) {
2266  if (canvas() && canvas()->needsWidgetMasks()) {
2267  // update our widget masks
2268  RenderLayer *p, *d = nullptr;
2269  for (p = layer()->parent(); p; p = p->parent())
2270  if (p->hasOverlaidWidgets()) {
2271  d = p;
2272  }
2273  if (d) { // deepest
2274  d->updateWidgetMasks(canvas()->layer());
2275  }
2276  }
2277  }
2278  if (layer() && !isInlineFlow()) {
2279  layer()->repaint(pri);
2280  } else {
2281  repaint(pri);
2282  }
2283  }
2284  }
2285 }
2286 
2287 bool RenderObject::attemptDirectLayerTranslation()
2288 {
2289  // When the difference between two successive styles is only 'Position'
2290  // we may attempt to save a layout by directly updating the object position.
2291 
2292  KHTMLAssert(m_style->position() != PSTATIC);
2293  if (!layer()) {
2294  return false;
2295  }
2296  setInline(m_style->isDisplayInlineType());
2297  setPositioned(m_style->position() != PRELATIVE);
2298  setRelPositioned(m_style->position() == PRELATIVE);
2299  int oldXPos = xPos();
2300  int oldYPos = yPos();
2301  int oldWidth = width();
2302  int oldHeight = height();
2303  calcWidth();
2304  calcHeight();
2305  if (oldWidth != width() || oldHeight != height()) {
2306  // implicit size change or overconstrained dimensions:
2307  // we'll need a layout.
2308  setWidth(oldWidth);
2309  setHeight(oldHeight);
2310  // qCDebug(KHTML_LOG) << "Layer translation failed for " << information();
2311  return false;
2312  }
2313  layer()->updateLayerPosition();
2314  if (m_style->position() != PFIXED) {
2315  bool needsDocSizeUpdate = true;
2316  RenderObject *cb = container();
2317  while (cb) {
2318  if (cb->hasOverflowClip() && cb->layer()) {
2319  cb->layer()->checkScrollbarsAfterLayout();
2320  needsDocSizeUpdate = false;
2321  break;
2322  }
2323  cb = cb->container();
2324  }
2325  if (needsDocSizeUpdate && canvas()) {
2326  bool posXOffset = (xPos() - oldXPos >= 0);
2327  bool posYOffset = (yPos() - oldYPos >= 0);
2328  canvas()->updateDocSizeAfterLayerTranslation(this, posXOffset, posYOffset);
2329  }
2330  }
2331  // success
2332  return true;
2333 }
2334 
2335 void RenderObject::dirtyFormattingContext(bool checkContainer)
2336 {
2337  if (m_markedForRepaint && !checkContainer) {
2338  return;
2339  }
2340  m_markedForRepaint = true;
2341  if (layer() && (style()->position() == PFIXED || style()->position() == PABSOLUTE)) {
2342  return;
2343  }
2344  if (m_parent && (checkContainer || style()->width().isAuto() || style()->height().isAuto() ||
2345  !(isFloating() || flowAroundFloats() || isTableCell()))) {
2346  m_parent->dirtyFormattingContext(false);
2347  }
2348 }
2349 
2350 void RenderObject::repaintDuringLayout()
2351 {
2352  if (canvas()->needsFullRepaint() || isText()) {
2353  return;
2354  }
2355  if (layer() && !isInlineFlow()) {
2356  layer()->repaint(NormalPriority, true);
2357  } else {
2358  repaint();
2359  canvas()->deferredRepaint(this);
2360  }
2361 }
2362 
2363 void RenderObject::updateBackgroundImages(RenderStyle *oldStyle)
2364 {
2365  // FIXME: This will be slow when a large number of images is used. Fix by using a dict.
2366  const BackgroundLayer *oldLayers = oldStyle ? oldStyle->backgroundLayers() : nullptr;
2367  const BackgroundLayer *newLayers = m_style ? m_style->backgroundLayers() : nullptr;
2368  for (const BackgroundLayer *currOld = oldLayers; currOld; currOld = currOld->next()) {
2369  if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage()))) {
2370  currOld->backgroundImage()->deref(this);
2371  }
2372  }
2373  for (const BackgroundLayer *currNew = newLayers; currNew; currNew = currNew->next()) {
2374  if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage()))) {
2375  currNew->backgroundImage()->ref(this);
2376  }
2377  }
2378 }
2379 
2380 QRect RenderObject::viewRect() const
2381 {
2382  return containingBlock()->viewRect();
2383 }
2384 
2385 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f) const
2386 {
2387  RenderObject *p = parent();
2388  if (p) {
2389  p->absolutePosition(xPos, yPos, f);
2390  if (p->hasOverflowClip()) {
2391  p->layer()->subtractScrollOffset(xPos, yPos);
2392  }
2393  return true;
2394  } else {
2395  xPos = yPos = 0;
2396  return false;
2397  }
2398 }
2399 
2400 void RenderObject::caretPos(int /*offset*/, int /*flags*/, int &_x, int &_y, int &width, int &height) const
2401 {
2402  _x = _y = height = -1;
2403  width = 1; // the caret has a default width of one pixel. If you want
2404  // to check for validity, only test the x-coordinate for >= 0.
2405 }
2406 
2407 int RenderObject::paddingTop() const
2408 {
2409  int w = 0;
2410  Length padding = m_style->paddingTop();
2411  if (padding.isPercent()) {
2412  w = containingBlock()->contentWidth();
2413  }
2414  w = padding.minWidth(w);
2415  if (isTableCell() && padding.isAuto()) {
2416  w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2417  }
2418  return w;
2419 }
2420 
2421 int RenderObject::paddingBottom() const
2422 {
2423  int w = 0;
2424  Length padding = style()->paddingBottom();
2425  if (padding.isPercent()) {
2426  w = containingBlock()->contentWidth();
2427  }
2428  w = padding.minWidth(w);
2429  if (isTableCell() && padding.isAuto()) {
2430  w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2431  }
2432  return w;
2433 }
2434 
2435 int RenderObject::paddingLeft() const
2436 {
2437  int w = 0;
2438  Length padding = style()->paddingLeft();
2439  if (padding.isPercent()) {
2440  w = containingBlock()->contentWidth();
2441  }
2442  w = padding.minWidth(w);
2443  if (isTableCell() && padding.isAuto()) {
2444  w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2445  }
2446  return w;
2447 }
2448 
2449 int RenderObject::paddingRight() const
2450 {
2451  int w = 0;
2452  Length padding = style()->paddingRight();
2453  if (padding.isPercent()) {
2454  w = containingBlock()->contentWidth();
2455  }
2456  w = padding.minWidth(w);
2457  if (isTableCell() && padding.isAuto()) {
2458  w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2459  }
2460  return w;
2461 }
2462 
2464 {
2465  // This method is extremely similar to containingBlock(), but with a few notable
2466  // exceptions.
2467  // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2468  // the object is not part of the primary document subtree yet.
2469  // (2) For normal flow elements, it just returns the parent.
2470  // (3) For absolute positioned elements, it will return a relative positioned inline.
2471  // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2472  // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
2473  // calcAbsoluteVertical have to use container().
2474  EPosition pos = m_style->position();
2475  RenderObject *o = nullptr;
2476  if (pos == PFIXED) {
2477  // container() can be called on an object that is not in the
2478  // tree yet. We don't call canvas() since it will assert if it
2479  // can't get back to the canvas. Instead we just walk as high up
2480  // as we can. If we're in the tree, we'll get the root. If we
2481  // aren't we'll get the root of our little subtree (most likely
2482  // we'll just return 0).
2483  o = parent();
2484  while (o && o->parent()) {
2485  o = o->parent();
2486  }
2487  } else if (pos == PABSOLUTE) {
2488  // Same goes here. We technically just want our containing block, but
2489  // we may not have one if we're part of an uninstalled subtree. We'll
2490  // climb as high as we can though.
2491  o = parent();
2492  while (o && o->style()->position() == PSTATIC && !o->isCanvas()) {
2493  o = o->parent();
2494  }
2495  } else {
2496  o = parent();
2497  }
2498  return o;
2499 }
2500 
2501 DOM::DocumentImpl *RenderObject::document() const
2502 {
2503  return m_node->document();
2504 }
2505 
2506 void RenderObject::removeFromObjectLists()
2507 {
2508  // in destruction mode, don't care.
2509  if (documentBeingDestroyed()) {
2510  return;
2511  }
2512 
2513  if (isFloating()) {
2514  RenderBlock *outermostBlock = containingBlock();
2515  for (RenderBlock *p = outermostBlock; p && !p->isCanvas() && p->containsFloat(this);) {
2516  outermostBlock = p;
2517  if (p->isFloatingOrPositioned()) {
2518  break;
2519  }
2520  p = p->containingBlock();
2521  }
2522 
2523  if (outermostBlock) {
2524  outermostBlock->markAllDescendantsWithFloatsForLayout(this);
2525  }
2526 
2527  RenderObject *p;
2528  for (p = parent(); p; p = p->parent()) {
2529  if (p->isRenderBlock()) {
2530  static_cast<RenderBlock *>(p)->removeFloatingObject(this);
2531  }
2532  }
2533 
2534  }
2535 
2536  if (inPosObjectList()) {
2537  RenderObject *p;
2538  for (p = parent(); p; p = p->parent()) {
2539  if (p->isRenderBlock()) {
2540  static_cast<RenderBlock *>(p)->removePositionedObject(this);
2541  }
2542  }
2543  }
2544 }
2545 
2546 RenderArena *RenderObject::renderArena() const
2547 {
2548  return m_node->document()->renderArena();
2549 }
2550 
2551 void RenderObject::detach()
2552 {
2553  detachCounters();
2554  remove();
2555 
2556  // make sure our DOM-node don't think we exist
2557  if (node() && node()->renderer() == this) {
2558  node()->setRenderer(nullptr);
2559  }
2560 
2561  // by default no refcounting
2562  arenaDelete(renderArena(), this);
2563 }
2564 
2565 void RenderObject::remove()
2566 {
2567  if (m_parent) {
2568  m_parent->removeChild(this);
2569  if (isFloating() || inPosObjectList()) {
2570  removeFromObjectLists();
2571  }
2572  }
2573 }
2574 
2575 void RenderObject::arenaDelete(RenderArena *arena, void *base)
2576 {
2577 #ifndef NDEBUG
2578  void *savedBase = baseOfRenderObjectBeingDeleted;
2579  baseOfRenderObjectBeingDeleted = base;
2580 #endif
2581  delete this;
2582 #ifndef NDEBUG
2583  baseOfRenderObjectBeingDeleted = savedBase;
2584 #endif
2585 
2586  // Recover the size left there for us by operator delete and free the memory.
2587  arena->free(*(size_t *)base, base);
2588 }
2589 
2590 void RenderObject::arenaDelete(RenderArena *arena)
2591 {
2592  // static_cast unfortunately doesn't work, since we multiple inherit
2593  // in eg. RenderWidget.
2594  arenaDelete(arena, dynamic_cast<void *>(this));
2595 }
2596 
2597 RenderPosition RenderObject::positionForCoordinates(int /*x*/, int /*y*/)
2598 {
2599  return RenderPosition(element(), caretMinOffset());
2600 }
2601 
2602 bool RenderObject::isPointInsideSelection(int x, int y, const Selection &sel) const
2603 {
2604  SelectionState selstate = selectionState();
2605  if (selstate == SelectionInside) {
2606  return true;
2607  }
2608  if (selstate == SelectionNone || !element()) {
2609  return false;
2610  }
2611  return element()->isPointInsideSelection(x, y, sel);
2612 }
2613 
2614 #if 0
2615 FindSelectionResult RenderObject::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl *&node, int &offset, SelPointState &state)
2616 {
2617 #if 0
2618  NodeInfo info(true, false);
2619  if (nodeAtPoint(info, _x, _y, _tx, _ty) && info.innerNode()) {
2620  RenderObject *r = info.innerNode()->renderer();
2621  if (r) {
2622  if (r == this) {
2623  node = info.innerNode();
2624  offset = 0; // we have no text...
2625  return SelectionPointInside;
2626  } else {
2627  return r->checkSelectionPoint(_x, _y, _tx, _ty, node, offset, state);
2628  }
2629  }
2630  }
2631  //qCDebug(KHTML_LOG) << "nodeAtPoint Failed. Fallback - hmm, SelectionPointAfter";
2632  node = 0;
2633  offset = 0;
2634  return SelectionPointAfter;
2635 #endif
2636  int off = offset;
2637  DOM::NodeImpl *nod = node;
2638 
2639  for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
2640  // ignore empty text boxes, they produce totally bogus information
2641  // for caret navigation (LS)
2642  if (child->isText() && !static_cast<RenderText *>(child)->firstTextBox()) {
2643  continue;
2644  }
2645 
2646 // qCDebug(KHTML_LOG) << "iterating " << (child ? child->renderName() : "") << "@" << child << (child->isText() ? " contains: \"" + QString::fromRawData(static_cast<RenderText *>(child)->text(), qMin(static_cast<RenderText *>(child)->length(), 10u)) + "\"" : QString());
2647 // qCDebug(KHTML_LOG) << "---------- checkSelectionPoint recursive -----------";
2648  khtml::FindSelectionResult pos = child->checkSelectionPoint(_x, _y, _tx + xPos(), _ty + yPos(), nod, off, state);
2649 // qCDebug(KHTML_LOG) << "-------- end checkSelectionPoint recursive ---------";
2650 // qCDebug(KHTML_LOG) << this << " child->findSelectionNode returned result=" << pos << " nod=" << nod << " off=" << off;
2651  switch (pos) {
2652  case SelectionPointBeforeInLine:
2653  case SelectionPointInside:
2654  //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint " << this << " returning SelectionPointInside offset=" << offset;
2655  node = nod;
2656  offset = off;
2657  return SelectionPointInside;
2658  case SelectionPointBefore:
2659  //x,y is before this element -> stop here
2660  if (state.m_lastNode) {
2661  node = state.m_lastNode;
2662  offset = state.m_lastOffset;
2663  //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint " << this << " before this child "
2664  // << node << "-> returning SelectionPointInside, offset=" << offset;
2665  return SelectionPointInside;
2666  } else {
2667  node = nod;
2668  offset = off;
2669  //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint " << this << " before us -> returning SelectionPointBefore " << node << "/" << offset;
2670  return SelectionPointBefore;
2671  }
2672  break;
2673  case SelectionPointAfter:
2674  if (state.m_afterInLine) {
2675  break;
2676  }
2677  // fall through
2678  case SelectionPointAfterInLine:
2679  if (pos == SelectionPointAfterInLine) {
2680  state.m_afterInLine = true;
2681  }
2682  //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint: selection after: " << nod << " offset: " << off << " afterInLine: " << state.m_afterInLine;
2683  state.m_lastNode = nod;
2684  state.m_lastOffset = off;
2685  // No "return" here, obviously. We must keep looking into the children.
2686  break;
2687  }
2688  }
2689  // If we are after the last child, return lastNode/lastOffset
2690  // But lastNode can be 0L if there is no child, for instance.
2691  if (state.m_lastNode) {
2692  node = state.m_lastNode;
2693  offset = state.m_lastOffset;
2694  }
2695  //qCDebug(KHTML_LOG) << "fallback - SelectionPointAfter node=" << node << " offset=" << offset;
2696  return SelectionPointAfter;
2697 }
2698 #endif
2699 
2700 bool RenderObject::mouseInside() const
2701 {
2702  if (!m_mouseInside && continuation()) {
2703  return continuation()->mouseInside();
2704  }
2705  return m_mouseInside;
2706 }
2707 
2708 bool RenderObject::nodeAtPoint(NodeInfo &info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside)
2709 {
2710  int tx = _tx + xPos();
2711  int ty = _ty + yPos();
2712 
2713  inside |= (style()->visibility() != HIDDEN &&
2714  (_y >= ty) && (_y < ty + height()) && (_x >= tx) && (_x < tx + width())) || isRoot() || isBody();
2715  bool inOverflowRect = inside;
2716  if (!inOverflowRect) {
2717  int ol = overflowLeft();
2718  int ot = overflowTop();
2719  QRect overflowRect(tx + ol, ty + ot, overflowWidth() - ol, overflowHeight() - ot);
2720  inOverflowRect = overflowRect.contains(_x, _y);
2721  }
2722 
2723  // ### table should have its own, more performant method
2724  if (hitTestAction != HitTestSelfOnly &&
2725  ((!isRenderBlock() ||
2726  !static_cast<RenderBlock *>(this)->isPointInScrollbar(_x, _y, _tx, _ty)) &&
2727  (inOverflowRect || isInline() || isRoot() || isCanvas() ||
2728  isTableRow() || isTableSection() || inside || mouseInside()))) {
2729  if (hitTestAction == HitTestChildrenOnly) {
2730  inside = false;
2731  }
2732  if (hasOverflowClip() && layer()) {
2733  layer()->subtractScrollOffset(tx, ty);
2734  }
2735  for (RenderObject *child = lastChild(); child; child = child->previousSibling())
2736  if (!child->layer() && child->nodeAtPoint(info, _x, _y, tx, ty, HitTestAll)) {
2737  inside = true;
2738  }
2739  }
2740 
2741  if (inside) {
2742  setInnerNode(info);
2743  }
2744 
2745  return inside;
2746 }
2747 
2748 void RenderObject::setInnerNode(NodeInfo &info)
2749 {
2750  if (!info.innerNode() && !isInline() && continuation()) {
2751  // We are in the margins of block elements that are part of a continuation. In
2752  // this case we're actually still inside the enclosing inline element that was
2753  // split. Go ahead and set our inner node accordingly.
2754  info.setInnerNode(continuation()->element());
2755  if (!info.innerNonSharedNode()) {
2756  info.setInnerNonSharedNode(continuation()->element());
2757  }
2758  }
2759 
2760  if (!info.innerNode() && element()) {
2761  info.setInnerNode(element());
2762  }
2763 
2764  if (!info.innerNonSharedNode() && element()) {
2765  info.setInnerNonSharedNode(element());
2766  }
2767 }
2768 
2769 short RenderObject::verticalPositionHint(bool firstLine) const
2770 {
2771  short vpos = m_verticalPosition;
2772  if (m_verticalPosition == PositionUndefined || firstLine) {
2773  vpos = getVerticalPosition(firstLine);
2774  if (!firstLine) {
2775  const_cast<RenderObject *>(this)->m_verticalPosition = vpos;
2776  }
2777  }
2778  return vpos;
2779 
2780 }
2781 
2782 short RenderObject::getVerticalPosition(bool firstLine, RenderObject *ref) const
2783 {
2784  // vertical align for table cells has a different meaning
2785  int vpos = 0;
2786  if (!isTableCell() && isInline()) {
2787  EVerticalAlign va = style()->verticalAlign();
2788  if (va == TOP) {
2789  vpos = PositionTop;
2790  } else if (va == BOTTOM) {
2791  vpos = PositionBottom;
2792  } else {
2793  if (!ref) {
2794  ref = parent();
2795  }
2796  bool checkParent = ref->isInline() && !ref->isReplacedBlock() &&
2797  !(ref->style()->verticalAlign() == TOP || ref->style()->verticalAlign() == BOTTOM);
2798  vpos = checkParent ? ref->verticalPositionHint(firstLine) : 0;
2799  // don't allow elements nested inside text-top to have a different valignment.
2800  if (va == BASELINE) {
2801  return vpos;
2802  } else if (va == LENGTH) {
2803  return vpos - style()->verticalAlignLength().width(lineHeight(firstLine));
2804  }
2805 
2806  const QFont &f = ref->font(firstLine);
2807  int fontsize = f.pixelSize();
2808 
2809  if (va == SUB) {
2810  vpos += fontsize / 5 + 1;
2811  } else if (va == SUPER) {
2812  vpos -= fontsize / 3 + 1;
2813  } else if (va == TEXT_TOP) {
2814  vpos += baselinePosition(firstLine) - (QFontMetrics(f).ascent() + QFontMetrics(f).leading() / 2);
2815  } else if (va == MIDDLE) {
2816  QRect b = QFontMetrics(f).boundingRect('x');
2817  vpos += -b.height() / 2 - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
2818  } else if (va == TEXT_BOTTOM) {
2819  vpos += QFontMetrics(f).descent() + QFontMetrics(f).leading() / 2;
2820  if (!isReplaced()) {
2821  vpos -= (lineHeight(firstLine) - baselinePosition(firstLine));
2822  }
2823  } else if (va == BASELINE_MIDDLE) {
2824  vpos += - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
2825  }
2826  }
2827  }
2828  return vpos;
2829 }
2830 
2831 short RenderObject::lineHeight(bool firstLine) const
2832 {
2833  // Inline blocks are replaced elements. Otherwise, just pass off to
2834  // the base class. If we're being queried as though we're the root line
2835  // box, then the fact that we're an inline-block is irrelevant, and we behave
2836  // just like a block.
2837 
2838  if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout())) {
2839  return height() + marginTop() + marginBottom();
2840  }
2841 
2842  Length lh;
2843  if (firstLine && hasFirstLine()) {
2844  RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LINE);
2845  if (pseudoStyle) {
2846  lh = pseudoStyle->lineHeight();
2847  }
2848  } else {
2849  lh = style()->lineHeight();
2850  }
2851 
2852  // its "unset", choose nice default
2853  if (lh.isNegative()) {
2854  return style()->htmlFont().lineSpacing();
2855  }
2856 
2857  if (lh.isPercent()) {
2858  return lh.minWidth(style()->font().pixelSize());
2859  }
2860 
2861  // its fixed
2862  return lh.value();
2863 }
2864 
2865 short RenderObject::baselinePosition(bool firstLine) const
2866 {
2867  // If we're an inline-block and need layout, it means our replaced boundaries
2868  // are not yet fully established, so we behave just like a block.
2869  if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout())) {
2870  return height() + marginTop() + marginBottom();
2871  }
2872 
2873  const QFontMetrics &fm = fontMetrics(firstLine);
2874  return fm.ascent() + (lineHeight(firstLine) - fm.height()) / 2;
2875 }
2876 
2877 void RenderObject::invalidateVerticalPosition()
2878 {
2879  m_verticalPosition = PositionUndefined;
2880 }
2881 
2882 void RenderObject::recalcMinMaxWidths()
2883 {
2884  KHTMLAssert(m_recalcMinMax);
2885 
2886 #ifdef DEBUG_LAYOUT
2887  qCDebug(KHTML_LOG) << renderName() << " recalcMinMaxWidths() this=" << this;
2888 #endif
2889 
2890  RenderObject *child = firstChild();
2891  int cmin = 0;
2892  int cmax = 0;
2893 
2894  while (child) {
2895  bool test = false;
2896  if ((m_minMaxKnown && child->m_recalcMinMax) || !child->m_minMaxKnown) {
2897  cmin = child->minWidth();
2898  cmax = child->maxWidth();
2899  test = true;
2900  }
2901  if (child->m_recalcMinMax) {
2902  child->recalcMinMaxWidths();
2903  }
2904  if (!child->m_minMaxKnown) {
2905  child->calcMinMaxWidth();
2906  }
2907  if (m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth())) {
2908  m_minMaxKnown = false;
2909  }
2910  child = child->nextSibling();
2911  }
2912 
2913  // we need to recalculate, if the contains inline children, as the change could have
2914  // happened somewhere deep inside the child tree
2915  if ((!isInline() || isReplacedBlock()) && childrenInline()) {
2916  m_minMaxKnown = false;
2917  }
2918 
2919  if (!m_minMaxKnown) {
2920  calcMinMaxWidth();
2921  }
2922  m_recalcMinMax = false;
2923 }
2924 
2925 void RenderObject::scheduleRelayout(RenderObject *clippedObj)
2926 {
2927  if (!isCanvas()) {
2928  return;
2929  }
2930  KHTMLView *view = static_cast<RenderCanvas *>(this)->view();
2931  if (view) {
2932  view->scheduleRelayout(clippedObj);
2933  }
2934 }
2935 
2936 InlineBox *RenderObject::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/)
2937 {
2938  KHTMLAssert(false);
2939  return nullptr;
2940 }
2941 
2942 void RenderObject::getTextDecorationColors(int decorations, QColor &underline, QColor &overline,
2943  QColor &linethrough, bool quirksMode)
2944 {
2945  RenderObject *curr = this;
2946  do {
2947  RenderStyle *st = curr->style();
2948  int currDecs = st->textDecoration();
2949  if (currDecs) {
2950  if (currDecs & UNDERLINE) {
2951  decorations &= ~UNDERLINE;
2952  underline = st->color();
2953  }
2954  if (currDecs & OVERLINE) {
2955  decorations &= ~OVERLINE;
2956  overline = st->color();
2957  }
2958  if (currDecs & LINE_THROUGH) {
2959  decorations &= ~LINE_THROUGH;
2960  linethrough = st->color();
2961  }
2962  }
2963  curr = curr->parent();
2964  if (curr && curr->isRenderBlock() && curr->continuation()) {
2965  curr = curr->continuation();
2966  }
2967  } while (curr && decorations && (!quirksMode || !curr->element() ||
2968  (curr->element()->id() != ID_A && curr->element()->id() != ID_FONT)));
2969 
2970  // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2971  if (decorations && curr) {
2972  RenderStyle *st = curr->style();
2973  if (decorations & UNDERLINE) {
2974  underline = st->color();
2975  }
2976  if (decorations & OVERLINE) {
2977  overline = st->color();
2978  }
2979  if (decorations & LINE_THROUGH) {
2980  linethrough = st->color();
2981  }
2982  }
2983 }
2984 
2985 int RenderObject::maximalOutlineSize(PaintAction p) const
2986 {
2987  if (p != PaintActionOutline) {
2988  return 0;
2989  }
2990  return static_cast<RenderCanvas *>(document()->renderer())->maximalOutlineSize();
2991 }
2992 
2993 void RenderObject::collectBorders(QList<CollapsedBorderValue> &borderStyles)
2994 {
2995  for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
2996  curr->collectBorders(borderStyles);
2997  }
2998 }
2999 
3000 bool RenderObject::flowAroundFloats() const
3001 {
3002  return isReplaced() || hasOverflowClip() || style()->flowAroundFloats();
3003 }
3004 
3005 bool RenderObject::usesLineWidth() const
3006 {
3007  // All auto-width objects that avoid floats should always use lineWidth
3008  // unless they are floating or inline. We only care about objects that grow
3009  // to fill the available space.
3010  return (!isInline() || isHTMLMarquee()) && flowAroundFloats() && style()->width().isAuto() && !isFloating();
3011 }
3012 
3014 {
3015  return 0;
3016 }
3017 
3019 {
3020  return 0;
3021 }
3022 
3023 unsigned long RenderObject::caretMaxRenderedOffset() const
3024 {
3025  return 0;
3026 }
3027 
3028 InlineBox *RenderObject::inlineBox(long /*offset*/)
3029 {
3030  if (isBox()) {
3031  return static_cast<RenderBox *>(this)->placeHolderBox();
3032  }
3033  return nullptr;
3034 }
3035 
3036 bool RenderObject::hasCounter(const DOMString &counter) const
3037 {
3038  if (style() && (!isText() || isCounter())) {
3039  if (lookupCounter(counter)) {
3040  return true;
3041  }
3042  if (style()->hasCounterReset(counter)) {
3043  return true;
3044  } else if (style()->hasCounterIncrement(counter)) {
3045  return true;
3046  }
3047  }
3048  if (counter == "list-item") {
3049  if (isListItem()) {
3050  return true;
3051  }
3052  if (element() && (
3053  element()->id() == ID_OL ||
3054  element()->id() == ID_UL ||
3055  element()->id() == ID_MENU ||
3056  element()->id() == ID_DIR)) {
3057  return true;
3058  }
3059  } else if (counter == "-khtml-quotes" && isQuote()) {
3060  return (static_cast<const RenderQuote *>(this)->quoteCount() != 0);
3061  }
3062  return false;
3063 }
3064 
3065 CounterNode *RenderObject::getCounter(const DOMString &counter, bool view, bool counters)
3066 {
3067 // qCDebug(KHTML_LOG) << renderName() << " getCounter(" << counter << ")";
3068 
3069  if (!style()) {
3070  return nullptr;
3071  }
3072 
3073  if (isText() && !isCounter()) {
3074  return nullptr;
3075  }
3076 
3077  CounterNode *i = lookupCounter(counter);
3078  if (i) {
3079  return i;
3080  }
3081  int val = 0;
3082 
3083  if (style()->hasCounterReset(counter) || isRoot()) {
3084  i = new CounterReset(this);
3085  val = style()->counterReset(counter);
3086  if (style()->hasCounterIncrement(counter)) {
3087  val += style()->counterIncrement(counter);
3088  }
3089 // qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3090  } else if (style()->hasCounterIncrement(counter)) {
3091  i = new CounterNode(this);
3092  val = style()->counterIncrement(counter);
3093 // qCDebug(KHTML_LOG) << renderName() << " counter-increment: " << counter << " " << val;
3094  } else if (counter == "list-item") {
3095  if (isListItem()) {
3096  if (element() && element()->id() == ID_LI) {
3097  DOMString v = static_cast<ElementImpl *>(element())->getAttribute(ATTR_VALUE);
3098  if (!v.isEmpty()) {
3099  i = new CounterReset(this);
3100  val = v.toInt();
3101 // qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3102  }
3103  }
3104  if (!i) {
3105  i = new CounterNode(this);
3106  val = 1;
3107 // qCDebug(KHTML_LOG) << renderName() << " counter-increment: " << counter << " " << val;
3108  }
3109  } else if (element() && element()->id() == ID_OL) {
3110  i = new CounterReset(this);
3111  DOMString v = static_cast<ElementImpl *>(element())->getAttribute(ATTR_START);
3112  if (!v.isEmpty()) {
3113  val = v.toInt() - 1;
3114  } else {
3115  val = 0;
3116  }
3117 // qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3118  } else if (element() &&
3119  (element()->id() == ID_UL ||
3120  element()->id() == ID_MENU ||
3121  element()->id() == ID_DIR)) {
3122  i = new CounterReset(this);
3123  val = 0;
3124 // qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3125  }
3126  } else if (counter == "-khtml-quotes" && isQuote()) {
3127  i = new CounterNode(this);
3128  val = static_cast<RenderQuote *>(this)->quoteCount();
3129  }
3130 
3131  if (!i) {
3132  i = new CounterNode(this);
3133  val = 0;
3134 // qCDebug(KHTML_LOG) << renderName() << " counter-increment: " << counter << " " << val;
3135  }
3136  i->setValue(val);
3137  if (view) {
3138  i->setIsVisual();
3139  }
3140  if (counters) {
3141  i->setHasCounters();
3142  }
3143 
3144  insertCounter(counter, i);
3145 
3146  if (!isRoot()) {
3147  CounterNode *last = nullptr, *current = nullptr;
3148  RenderObject *n = previousSibling();
3149  while (n) {
3150  if (n->hasCounter(counter)) {
3151  current = n->getCounter(counter);
3152  break;
3153  } else {
3154  n = n->previousSibling();
3155  }
3156  }
3157  last = current;
3158 
3159  CounterNode *sibling = current;
3160  // counter-reset on same render-level is our counter-parent
3161  if (last) {
3162  // Found render-sibling, now search for later counter-siblings among its render-children
3163  n = n->lastChild();
3164  while (n) {
3165  if (n->hasCounter(counter)) {
3166  current = n->getCounter(counter);
3167  if (last->parent() == current->parent() || sibling == current->parent()) {
3168  last = current;
3169  // If the current counter is not the last, search deeper
3170  if (current->nextSibling()) {
3171  n = n->lastChild();
3172  continue;
3173  } else {
3174  break;
3175  }
3176  }
3177  }
3178  n = n->previousSibling();
3179  }
3180  if (sibling->isReset()) {
3181  if (last != sibling) {
3182  sibling->insertAfter(i, last);
3183  } else {
3184  sibling->insertAfter(i, nullptr);
3185  }
3186  } else if (last->parent()) {
3187  last->parent()->insertAfter(i, last);
3188  }
3189  } else if (parent()) {
3190  // Nothing found among siblings, let our parent search
3191  last = parent()->getCounter(counter, false);
3192  if (last->isReset()) {
3193  last->insertAfter(i, nullptr);
3194  } else if (last->parent()) {
3195  last->parent()->insertAfter(i, last);
3196  }
3197  }
3198  }
3199 
3200  return i;
3201 }
3202 
3203 CounterNode *RenderObject::lookupCounter(const DOMString &counter) const
3204 {
3205  QHash<DOMString, khtml::CounterNode *> *counters = document()->counters(this);
3206  return counters ? counters->value(counter) : nullptr;
3207 }
3208 
3209 void RenderObject::detachCounters()
3210 {
3211  QHash<DOMString, khtml::CounterNode *> *counters = document()->counters(this);
3212  if (!counters) {
3213  return;
3214  }
3215 
3217 
3218  while (i.hasNext()) {
3219  i.next();
3220  i.value()->remove();
3221  delete i.value();
3222  }
3223  document()->removeCounters(this);
3224 }
3225 
3226 void RenderObject::insertCounter(const DOMString &counter, CounterNode *val)
3227 {
3228  QHash<DOMString, khtml::CounterNode *> *counters = document()->counters(this);
3229 
3230  if (!counters) {
3231  counters = new QHash<DOMString, khtml::CounterNode *>();
3232  document()->setCounters(this, counters);
3233  }
3234 
3235  counters->insert(counter, val);
3236 }
3237 
3238 void RenderObject::updateWidgetMasks()
3239 {
3240  for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
3241  if (curr->isWidget() && static_cast<RenderWidget *>(curr)->needsMask()) {
3242  QWidget *w = static_cast<RenderWidget *>(curr)->widget();
3243  if (!w) {
3244  return;
3245  }
3246  RenderLayer *l = curr->enclosingStackingContext();
3247  QRegion r = l ? l->getMask() : QRegion();
3248  int x, y;
3249  if (!r.isEmpty() && curr->absolutePosition(x, y)) {
3250  int pbx = curr->borderLeft() + curr->paddingLeft();
3251  int pby = curr->borderTop() + curr->paddingTop();
3252  x += pbx;
3253  y += pby;
3254  r = r.intersect(QRect(x, y,
3255  curr->width() - pbx - curr->borderRight() - curr->paddingRight(),
3256  curr->height() - pby - curr->borderBottom() - curr->paddingBottom()));
3257 #ifdef MASK_DEBUG
3258  QVector<QRect> ar = r.rects();
3259  qCDebug(KHTML_LOG) << "|| Setting widget mask for " << curr->information();
3260  for (int i = 0; i < ar.size(); ++i) {
3261  qCDebug(KHTML_LOG) << " " << ar[i];
3262  }
3263 #endif
3264  r.translate(-x, -y);
3265 
3266  // ### Scrollarea's widget doesn't update when mask change.
3267  // Might be a Qt bug. Might be the way we handle updates. Investigate.
3268  if (::qobject_cast<QScrollArea *>(w)) {
3269  QScrollArea *sa = static_cast<QScrollArea *>(w);
3270  if (!w->mask().isEmpty()) {
3271  QPoint off(sa->horizontalScrollBar()->value(),
3272  sa->verticalScrollBar()->value());
3273  sa->widget()->update(w->mask().translated(off));
3274  sa->horizontalScrollBar()->update();
3275  sa->verticalScrollBar()->update();
3276  }
3277  }
3278  w->setMask(r);
3279  } else {
3280  w->clearMask();
3281  }
3282  } else if (!curr->layer() || !curr->layer()->isStackingContext()) {
3283  curr->updateWidgetMasks();
3284  }
3285 
3286  }
3287 }
3288 
3289 QRegion RenderObject::visibleFlowRegion(int x, int y) const
3290 {
3291  QRegion r;
3292  bool returnSelf = false;
3293  for (RenderObject *ro = firstChild(); ro; ro = ro->nextSibling()) {
3294  if (!ro->layer() && !ro->isFloating() && ro->style()->visibility() == VISIBLE) {
3295  const RenderStyle *s = ro->style();
3296  int ow = s->outlineSize();
3297  if (ro->isInlineFlow() || ro->isText()) {
3298  returnSelf = true;
3299  break;
3300  }
3301  if (s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() || ro->isReplaced() || ow) {
3302  r += QRect(x - ow + ro->effectiveXPos(), y - ow + ro->effectiveYPos(),
3303  ro->effectiveWidth() + ow * 2, ro->effectiveHeight() + ow * 2);
3304  } else {
3305  r += ro->visibleFlowRegion(x + ro->xPos(), y + ro->yPos());
3306  }
3307  }
3308  }
3309  if (hasFloats()) {
3310  r += static_cast<const RenderBlock *>(this)->visibleFloatingRegion(x, y);
3311  }
3312  if (returnSelf) {
3313  int ow = style()->outlineSize();
3314  r += QRect(x - xPos() - ow + effectiveXPos(), y - yPos() - ow + effectiveYPos(),
3315  effectiveWidth() + ow * 2, effectiveHeight() + ow * 2);
3316  }
3317  return r;
3318 }
3319 
3320 // SVG
3321 FloatRect RenderObject::relativeBBox(bool includeStroke) const
3322 {
3323  Q_UNUSED(includeStroke);
3324  return FloatRect();
3325 }
3326 
3327 AffineTransform RenderObject::localTransform() const
3328 {
3329  return AffineTransform(1, 0, 0, 1, xPos(), yPos());
3330 }
3331 
3332 AffineTransform RenderObject::absoluteTransform() const
3333 {
3334  if (parent()) {
3335  return localTransform() * parent()->absoluteTransform();
3336  }
3337  return localTransform();
3338 }
3339 // END SVG
3340 
3341 #undef RED_LUMINOSITY
3342 #undef GREEN_LUMINOSITY
3343 #undef BLUE_LUMINOSITY
3344 #undef INTENSITY_FACTOR
3345 #undef LIGHT_FACTOR
3346 #undef LUMINOSITY_FACTOR
3347 
3348 #undef MAX_COLOR
3349 #undef COLOR_DARK_THRESHOLD
3350 #undef COLOR_LIGHT_THRESHOLD
3351 
3352 #undef COLOR_LITE_BS_FACTOR
3353 #undef COLOR_LITE_TS_FACTOR
3354 
3355 #undef COLOR_DARK_BS_FACTOR
3356 #undef COLOR_DARK_TS_FACTOR
3357 
3358 #undef LIGHT_GRAY
3359 #undef DARK_GRAY
3360 
bool hasClipping() const const
QHash::iterator insert(const Key &key, const T &value)
int ascent() const const
int & rx()
int & ry()
bool m_afterInLine
true when the last node had the result SelectionAfterInLine
int width() const const
bool end()
int pixelSize() const const
QString & fill(QChar ch, int size)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setCompositionMode(QPainter::CompositionMode mode)
QPixmap copy(int x, int y, int width, int height) const const
void setRenderHint(QPainter::RenderHint hint, bool on)
Format_ARGB32_Premultiplied
void translate(int dx, int dy)
void fill(const QColor &color)
qreal x() const const
qreal y() const const
void closeSubpath()
void setColorAt(qreal position, const QColor &color)
QWidget * widget() const const
bool hasNext() const const
This file is part of the HTML rendering engine for KDE.
int contentsY() const
Returns the y coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:714
int effectiveXPos() const
the position of the object from where it begins drawing, including its negative overflow ...
bool intersects(const QRect &rectangle) const const
void save()
int descent() const const
void setAlpha(int alpha)
virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const
Returns the content coordinates of the caret within this render object.
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
void drawTiledPixmap(const QRectF &rectangle, const QPixmap &pixmap, const QPointF &position)
int height() const const
QTextStream & endl(QTextStream &stream)
QRect boundingRect() const const
int x() const const
int y() const const
void setRgb(int r, int g, int b, int a)
QPaintEngine * paintEngine() const const
void update()
a cached image
Definition: loader.h:359
int x() const const
int y() const const
const QColor & color() const const
KHTMLView * view() const
Returns a pointer to the HTML document&#39;s view.
void drawRect(const QRectF &rectangle)
QRect boundingRect(QChar ch) const const
QString fromRawData(const QChar *unicode, int size)
QTransform & translate(qreal dx, qreal dy)
QString number(int n, int base)
void append(const T &value)
void setTransform(const QTransform &matrix)
QTransform & scale(qreal sx, qreal sy)
void fill(uint pixelValue)
int top() const const
QPainter::CompositionMode compositionMode() const const
QRegion clipRegion() const const
void fillPath(const QPainterPath &path, const QBrush &brush)
int red() const const
void setPen(const QColor &color)
void lineTo(const QPointF &endPoint)
int effectiveWidth() const
Returns the width that is effectively considered when contemplating the object as a whole – usually ...
int left() const const
void setMask(const QBitmap &bitmap)
RenderObject * container() const
returns the object containing this one.
QRegion translated(int dx, int dy) const const
DOM::NodeImpl * m_lastNode
last node that was before the current position
virtual long caretMinOffset() const
returns the lowest possible value the caret offset may have to still point to a valid position...
void addRect(const QRectF &rectangle)
void arcMoveTo(const QRectF &rectangle, qreal angle)
void setBrush(const QBrush &brush)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
QScrollBar * verticalScrollBar() const const
void clearMask()
int alpha() const const
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
int green() const const
const T value(const Key &key) const const
CompositionMode_Difference
QHashIterator::Item next()
int height() const const
long m_lastOffset
offset of last node
int leading() const const
virtual long caretMaxOffset() const
returns the highest possible value the caret offset may have to still point to a valid position...
void restore()
This library provides a full-featured HTML parser and widget.
int blue() const const
QDataStream & operator<<(QDataStream &out, const KDateTime::Spec &spec)
bool contains(const QRect &rectangle, bool proper) const const
bool isNull() const const
int width() const const
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags)
qreal width() const const
char * toString(const T &value)
KIOFILEWIDGETS_EXPORT QString dir(const QString &fileClass)
void drawConvexPolygon(const QPointF *points, int pointCount)
virtual int inlineXPos() const
Leftmost coordinate of this inline element relative to containing block.
int effectiveYPos() const
the position of the object from where it begins drawing, including its negative overflow ...
int contentsX() const
Returns the x coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:709
int height() const const
Base Class for all rendering tree objects.
QSize size() const const
bool isEmpty() const const
QScrollBar * horizontalScrollBar() const const
qreal height() const const
bool hasFeature(QPaintEngine::PaintEngineFeatures feature) const const
QVector< QRect > rects() const const
const T & value() const const
contains stateful information for a checkSelectionPoint call
int size() const const
bool begin(QPaintDevice *device)
virtual int inlineYPos() const
Topmost coordinate of this inline element relative to containing block.
int effectiveHeight() const
Returns the height that is effectively considered when contemplating the object as a whole – usually...
void arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
QRegion mask() const const
QRgb rgba() const const
bool isValid() const const
QRegion intersect(const QRegion &r) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 25 2021 22:48:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.