KHtml

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

KDE's Doxygen guidelines are available online.