KHtml

render_replaced.cpp
1 /**
2 * This file is part of the HTML widget for KDE.
3 *
4 * Copyright (C) 1999-2003 Lars Knoll ([email protected])
5 * (C) 2000-2003 Dirk Mueller ([email protected])
6 * (C) 2003 Apple Computer, Inc.
7 * (C) 2004-2006 Germain Garand ([email protected])
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25 #include "render_replaced.h"
26 #include "render_layer.h"
27 #include "render_canvas.h"
28 #include "render_line.h"
29 #include "rendering/render_position.h"
30 
31 #include "render_arena.h"
32 
33 #include <assert.h>
34 #include <QWidget>
35 #include <QPainter>
36 #include <QActionEvent>
37 #include <QApplication>
38 #include <QLineEdit>
39 #include <QComboBox>
40 #include <QCheckBox>
41 #include <QRadioButton>
42 #include <kurlrequester.h>
43 #include <QVector>
44 #include <QMatrix>
45 #include <QPaintEngine>
46 
47 #include "khtml_ext.h"
48 #include "khtmlview.h"
49 #include "xml/dom2_eventsimpl.h"
50 #include "khtml_part.h"
51 #include "xml/dom_docimpl.h"
52 #include "xml/dom_position.h"
53 #include "misc/helper.h"
54 #include "misc/paintbuffer.h"
55 #include "css/cssvalues.h"
56 
57 #include <kcolorscheme.h>
58 #include "khtml_debug.h"
59 
60 //#define IN_PLACE_WIDGET_PAINTING
61 
63 
64 using namespace khtml;
65 using namespace DOM;
66 
67 RenderReplaced::RenderReplaced(DOM::NodeImpl *node)
68  : RenderBox(node)
69 {
70  // init RenderObject attributes
71  setReplaced(true);
72 
73  m_intrinsicWidth = 300;
74  m_intrinsicHeight = 150;
75 }
76 
77 void RenderReplaced::calcMinMaxWidth()
78 {
79  KHTMLAssert(!minMaxKnown());
80 
81 #ifdef DEBUG_LAYOUT
82  // qCDebug(KHTML_LOG) << "RenderReplaced::calcMinMaxWidth() known=" << minMaxKnown();
83 #endif
84 
85  m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
86 
87  if (style()->width().isPercent() || style()->height().isPercent() ||
88  style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
89  style()->minWidth().isPercent() || style()->minHeight().isPercent()) {
90  m_minWidth = 0;
91  m_maxWidth = m_width;
92  } else {
93  m_minWidth = m_maxWidth = m_width;
94  }
95 
96  setMinMaxKnown();
97 }
98 
99 FindSelectionResult RenderReplaced::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl *&node, int &offset, SelPointState &)
100 {
101 #if 0
102  // qCDebug(KHTML_LOG) << "RenderReplaced::checkSelectionPoint(_x="<<_x<<",_y="<<_y<<",_tx="<<_tx<<",_ty="<<_ty<<")" << endl
103  << "xPos: " << xPos() << " yPos: " << yPos() << " width: " << width() << " height: " << height() << endl
104  << "_ty + yPos: " << (_ty + yPos()) << " + height: " << (_ty + yPos() + height()) << "; _tx + xPos: " << (_tx + xPos()) << " + width: " << (_tx + xPos() + width());
105 #endif
106  node = element();
107  offset = 0;
108 
109  if (_y < _ty + yPos()) {
110  return SelectionPointBefore; // above -> before
111  }
112 
113  if (_y > _ty + yPos() + height()) {
114  // below -> after
115  // Set the offset to the max
116  offset = 1;
117  return SelectionPointAfter;
118  }
119  if (_x > _tx + xPos() + width()) {
120  // to the right
121  // ### how to regard bidi in replaced elements? (LS)
122  offset = 1;
123  return SelectionPointAfterInLine;
124  }
125 
126  // The Y matches, check if we're on the left
127  if (_x < _tx + xPos()) {
128  // ### how to regard bidi in replaced elements? (LS)
129  return SelectionPointBeforeInLine;
130  }
131 
132  offset = _x > _tx + xPos() + width() / 2;
133  return SelectionPointInside;
134 }
135 
136 long RenderReplaced::caretMinOffset() const
137 {
138  return 0;
139 }
140 
141 // Returns 1 since a replaced element can have the caret positioned
142 // at its beginning (0), or at its end (1).
143 long RenderReplaced::caretMaxOffset() const
144 {
145  return 1;
146 }
147 
148 unsigned long RenderReplaced::caretMaxRenderedOffset() const
149 {
150  return 1;
151 }
152 
153 RenderPosition RenderReplaced::positionForCoordinates(int _x, int _y)
154 {
155  InlineBox *box = placeHolderBox();
156  if (!box) {
157  return RenderPosition(element(), 0);
158  }
159 
160  RootInlineBox *root = box->root();
161 
162  int absx, absy;
163  containingBlock()->absolutePosition(absx, absy);
164 
165  int top = absy + root->topOverflow();
166  int bottom = root->nextRootBox() ? absy + root->nextRootBox()->topOverflow() : absy + root->bottomOverflow();
167 
168  if (_y < top) {
169  return RenderPosition(element(), caretMinOffset()); // coordinates are above
170  }
171 
172  if (_y >= bottom) {
173  return RenderPosition(element(), caretMaxOffset()); // coordinates are below
174  }
175 
176  if (element()) {
177  if (_x <= absx + xPos() + (width() / 2)) {
178  return RenderPosition(element(), 0);
179  }
180  return RenderPosition(element(), 1);
181  }
182 
183  return RenderBox::positionForCoordinates(_x, _y);
184 }
185 
186 // -----------------------------------------------------------------------------
187 
188 RenderWidget::RenderWidget(DOM::NodeImpl *node)
189  : RenderReplaced(node)
190 {
191  m_widget = nullptr;
192  m_underMouse = nullptr;
193  m_buffer[0] = nullptr;
194  m_buffer[1] = nullptr;
195  m_nativeFrameShape = QFrame::NoFrame;
196  // a widget doesn't support being anonymous
197  assert(!isAnonymous());
198  m_view = node->document()->view();
199  m_arena.reset(renderArena());
200  m_needsMask = false;
201  m_ownsWidget = true;
202 
203  // this is no real reference counting, it is just there
204  // to make sure that we're not deleted while we're recursed
205  // in an eventFilter of the widget
206  ref();
207 }
208 
209 void RenderWidget::detach()
210 {
211  // warning: keep in sync with RenderObject::detach
212 
213  detachCounters();
214  remove();
215 
216  if (m_widget) {
217  if (m_view) {
218  m_view->setWidgetVisible(this, false);
219  }
220  KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget);
221  if (k) {
222  k->m_kwp->setRenderWidget(nullptr);
223  }
224  m_widget->removeEventFilter(this);
225  m_widget->setMouseTracking(false);
226  }
227 
228  // make sure our DOM-node don't think we exist
229  if (node() && node()->renderer() == this) {
230  node()->setRenderer(nullptr);
231  }
232 
233  setDetached();
234  deref();
235 }
236 
237 RenderWidget::~RenderWidget()
238 {
239  KHTMLAssert(refCount() <= 0);
240 
241  if (m_widget) {
242  if (m_widget->hasFocus()) {
243  m_widget->clearFocus();
244  }
245  m_widget->hide();
246  if (m_ownsWidget) {
247  m_widget->deleteLater();
248  }
249  }
250  delete m_buffer[0];
251  delete m_buffer[1];
252 }
253 
254 class QWidgetResizeEvent : public QEvent
255 {
256 public:
257  enum { Type = QEvent::User + 0xbee };
258  QWidgetResizeEvent(int _w, int _h) :
259  QEvent((QEvent::Type) Type), w(_w), h(_h) {}
260  int w;
261  int h;
262 };
263 
264 void RenderWidget::resizeWidget(int w, int h)
265 {
266  // ugly hack to limit the maximum size of the widget ( as X11 has problems if
267  // it is bigger )
268  h = qMin(h, 3072);
269  w = qMin(w, 2000);
270 
271  if (m_widget->width() != w || m_widget->height() != h) {
272  m_widget->resize(w, h);
273  if (isRedirectedWidget() && qobject_cast<KHTMLView *>(m_widget) && !m_widget->isVisible()) {
274  // Emission of Resize event is delayed.
275  // we have to pre-call KHTMLView::resizeEvent
276  // so that viewport size change and subsequent layout update
277  // is effective synchronously, which is important for JS.
278  // This only work because m_widget is a redirected view,
279  // and thus has visibleWidth()/visibleHeight() that mirror this RenderWidget,
280  // rather than the effective widget size. - gg.
281  QResizeEvent e(QSize(w, h), QSize(m_widget->width(), m_widget->height()));
282  static_cast<KHTMLView *>(m_widget)->resizeEvent(&e);
283  }
284  }
285 }
286 
287 bool RenderWidget::event(QEvent *e)
288 {
289  // eat all events - except if this is a frame (in which case KHTMLView handles it all)
290  if (qobject_cast<KHTMLView *>(m_widget)) {
291  return QObject::event(e);
292  }
293  return true;
294 }
295 
296 bool RenderWidget::isRedirectedWidget() const
297 {
298  KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget);
299  return k ? k->m_kwp->isRedirected() : false;
300 }
301 
302 void RenderWidget::setQWidget(QWidget *widget)
303 {
304  if (widget != m_widget) {
305  if (m_widget) {
306  m_widget->removeEventFilter(this);
307  disconnect(m_widget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestructed()));
308  m_widget->hide();
309  if (m_ownsWidget) {
310  m_widget->deleteLater(); //Might happen due to event on the widget, so be careful
311  }
312  m_widget = nullptr;
313  }
314  m_widget = widget;
315  if (m_widget) {
316  KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget);
317  bool isRedirectedSubFrame = false;
318  if (k) {
319  k->m_kwp->setRenderWidget(this);
320  // enable redirection of every sub-frame that is not a FRAME
321  if (qobject_cast<KHTMLView *>(m_widget) && element() && element()->id() != ID_FRAME) {
322  k->m_kwp->setIsRedirected(true);
323  isRedirectedSubFrame = true;
324  }
325  }
326  m_widget->setParent(m_view->widget());
327  if (isRedirectedSubFrame) {
328  static_cast<KHTMLView *>(m_widget)->setHasStaticBackground();
329  }
330  connect(m_widget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestructed()));
331  m_widget->installEventFilter(this);
332  if (isRedirectedWidget()) {
333  if (!qobject_cast<QFrame *>(m_widget)) {
334  m_widget->setAttribute(Qt::WA_NoSystemBackground);
335  }
336  }
337  if (m_widget->focusPolicy() > Qt::StrongFocus) {
338  m_widget->setFocusPolicy(Qt::StrongFocus);
339  }
340  // if we've already received a layout, apply the calculated space to the
341  // widget immediately, but we have to have really been full constructed (with a non-null
342  // style pointer).
343  if (!needsLayout() && style()) {
344  resizeWidget(m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(),
345  m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom());
346  } else {
347  setPos(xPos(), -500000);
348  }
349  }
350  m_view->setWidgetVisible(this, false);
351  if (m_widget) {
352  m_widget->move(0, -500000);
353  m_widget->hide();
354  }
355  }
356 }
357 
358 void RenderWidget::layout()
359 {
360  KHTMLAssert(needsLayout());
361  KHTMLAssert(minMaxKnown());
362  if (m_widget) {
363  resizeWidget(m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(),
364  m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom());
365  if (!isRedirectedWidget() && (!isFrame() || document()->part()->parentPart()) && !m_needsMask) {
366  m_needsMask = true;
367  RenderLayer *rl = enclosingStackingContext();
368  RenderLayer *el = enclosingLayer();
369  while (rl && el && el != rl) {
370  if (el->renderer()->style()->position() != PSTATIC) {
371  m_needsMask = false;
372  break;
373  }
374  el = el->parent();
375  }
376  if (m_needsMask) {
377  if (rl) {
378  rl->setHasOverlaidWidgets();
379  }
380  canvas()->setNeedsWidgetMasks();
381  }
382  }
383  }
384 
385  setNeedsLayout(false);
386 }
387 
388 void RenderWidget::updateFromElement()
389 {
390  if (m_widget && !qobject_cast<KHTMLView *>(m_widget)) {
391  // Color:
392  QColor color = style()->color();
393  if (forceTransparentText()) {
394  color = Qt::transparent;
395  }
396  QColor backgroundColor = style()->backgroundColor();
397 
398  if (!backgroundColor.isValid() && !style()->htmlHacks()) {
399  backgroundColor = Qt::transparent;
400  }
401 
402  bool hasBackgroundImage = style()->hasBackgroundImage();
403  // check if we have to paint our background and let it show through the widget
404  bool trans = (isRedirectedWidget() && !qobject_cast<KUrlRequester *>(m_widget) &&
405  (hasBackgroundImage || (style()->hasBackground() && shouldPaintCSSBorders())));
406 
407  QPalette pal(QApplication::palette(m_widget));
408  // We need a non-transparent version for widgets with popups (e.g. kcombobox). The popups must not let
409  // the background show through.
410  QPalette non_trans_pal = pal;
411 
412  if (color.isValid() || backgroundColor.isValid() || trans) {
413  int contrast_ = KColorScheme::contrast();
414  int highlightVal = 100 + (2 * contrast_ + 4) * 16 / 10;
415  int lowlightVal = 100 + (2 * contrast_ + 4) * 10;
416  bool shouldChangeBgPal = true;
417 
418  if (!backgroundColor.isValid()) {
419  backgroundColor = pal.color(widget()->backgroundRole());
420  } else
421  shouldChangeBgPal = !((backgroundColor == colorForCSSValue(CSS_VAL_WINDOW)) ||
422  (backgroundColor == colorForCSSValue(CSS_VAL_BUTTONFACE)));
423  if (shouldChangeBgPal || trans) {
424  pal.setColor(widget()->backgroundRole(), trans ? QColor(0, 0, 0, 0) : backgroundColor);
425  for (int i = 0; i < QPalette::NColorGroups; ++i) {
426  if (shouldChangeBgPal) {
427  pal.setColor((QPalette::ColorGroup)i, QPalette::Window, backgroundColor);
428  pal.setColor((QPalette::ColorGroup)i, QPalette::Light, backgroundColor.lighter(highlightVal));
429  pal.setColor((QPalette::ColorGroup)i, QPalette::Dark, backgroundColor.darker(lowlightVal));
430  pal.setColor((QPalette::ColorGroup)i, QPalette::Mid, backgroundColor.darker(120));
431  pal.setColor((QPalette::ColorGroup)i, QPalette::Midlight, backgroundColor.lighter(110));
432  }
433  pal.setColor((QPalette::ColorGroup)i, QPalette::Button, trans ? QColor(0, 0, 0, 0) : backgroundColor);
434  pal.setColor((QPalette::ColorGroup)i, QPalette::Base, trans ? QColor(0, 0, 0, 0) : backgroundColor);
435  }
436  }
437 
438  if (color.isValid()) {
439  struct ColorSet {
442  };
443  const struct ColorSet toSet [] = {
447  { QPalette::Inactive, QPalette::WindowText },
448  { QPalette::Inactive, QPalette::ButtonText },
449  { QPalette::Inactive, QPalette::Text },
451  };
452  const ColorSet *set = toSet;
453  while (set->cg != QPalette::NColorGroups) {
454  pal.setColor(set->cg, set->cr, color);
455  non_trans_pal.setColor(set->cg, set->cr, color);
456  ++set;
457  }
458 
459  QColor disfg = color;
460  int h, s, v;
461  disfg.getHsv(&h, &s, &v);
462  if (v > 128)
463  // dark bg, light fg - need a darker disabled fg
464  {
465  disfg = disfg.darker(lowlightVal);
466  } else if (v > 64)
467  // light bg, dark fg - need a lighter disabled fg - but only if !black
468  {
469  disfg = disfg.lighter(highlightVal);
470  } else
471  // for really dark fg - use darkgray disabled fg,
472  // as ::light is pretty useless in this range
473  {
474  disfg = Qt::darkGray;
475  }
479  non_trans_pal.setColor(QPalette::Disabled, QPalette::WindowText, disfg);
480  non_trans_pal.setColor(QPalette::Disabled, QPalette::Text, disfg);
481  non_trans_pal.setColor(QPalette::Disabled, QPalette::ButtonText, disfg);
482  }
483  }
484 
485  if ((qobject_cast<QCheckBox *>(m_widget) || qobject_cast<QRadioButton *>(m_widget)) &&
486  (backgroundColor == Qt::transparent && !hasBackgroundImage)) {
487  m_widget->setPalette(non_trans_pal);
488  } else {
489  m_widget->setPalette(pal);
490  }
491 
492  // Combobox's popup colors
493  if (qobject_cast<QComboBox *>(m_widget)) {
494  // Background
495  if (hasBackgroundImage) {
496  non_trans_pal = QApplication::palette();
497  } else if (backgroundColor.isValid() && backgroundColor != Qt::transparent) {
498  non_trans_pal.setColor(QPalette::Base, backgroundColor);
499  }
500  // mmh great, there's no accessor for the popup...
501  QList<QWidget *>l = m_widget->findChildren<QWidget *>();
502  foreach (QWidget *w, l) {
503  if (QAbstractScrollArea *lView = qobject_cast<QAbstractScrollArea *>(w)) {
504  // we have the listview, climb up to reach its container.
505  assert(w->parentWidget() != m_widget);
506  if (w->parentWidget()) {
507  w->parentWidget()->setPalette(non_trans_pal);
508  // Set system color for vertical scrollbar
509  lView->verticalScrollBar()->setPalette(QApplication::palette());
510  }
511  }
512  }
513  } else if (QAbstractScrollArea *scrollView = qobject_cast<QAbstractScrollArea *>(m_widget)) {
514  // Border
515  if (QFrame *frame = qobject_cast<QFrame *>(m_widget)) {
516  if (shouldDisableNativeBorders()) {
517  if (frame->frameShape() != QFrame::NoFrame) {
518  m_nativeFrameShape = frame->frameShape();
519  frame->setFrameShape(QFrame::NoFrame);
520  }
521  } else if (m_nativeFrameShape != QFrame::NoFrame) {
522  frame->setFrameShape(m_nativeFrameShape);
523  }
524  }
525  // Scrollbars color (ie css extension)
526  scrollView->horizontalScrollBar()->setPalette(style()->palette());
527  scrollView->verticalScrollBar()->setPalette(style()->palette());
528  } else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_widget)) {
529  lineEdit->setFrame(!shouldDisableNativeBorders());
530  }
531  }
532 
533  RenderReplaced::updateFromElement();
534 }
535 
536 void RenderWidget::paintBoxDecorations(PaintInfo &paintInfo, int _tx, int _ty)
537 {
538  QRect r = QRect(_tx, _ty, width(), height());
539  QRect cr = r.intersected(paintInfo.r);
540 
541  if (qobject_cast<QAbstractScrollArea *>(m_widget) || (isRedirectedWidget() &&
542  (style()->hasBackgroundImage() || (style()->hasBackground() && shouldPaintCSSBorders())))) {
543  paintAllBackgrounds(paintInfo.p, style()->backgroundColor(), style()->backgroundLayers(),
544  cr, r.x(), r.y(), r.width(), r.height());
545  }
546 
547  if (shouldPaintCSSBorders() && style()->hasBorder()) {
548  paintBorder(paintInfo.p, _tx, _ty, width(), height(), style());
549  }
550 }
551 
552 void RenderWidget::slotWidgetDestructed()
553 {
554  if (m_view) {
555  m_view->setWidgetVisible(this, false);
556  }
557  m_widget = nullptr;
558 }
559 
560 void RenderWidget::setStyle(RenderStyle *_style)
561 {
562  RenderReplaced::setStyle(_style);
563  if (m_widget) {
564  m_widget->setFont(style()->font());
565  if (style()->visibility() != VISIBLE) {
566  if (m_view) {
567  m_view->setWidgetVisible(this, false);
568  }
569  m_widget->hide();
570  }
571  }
572 }
573 
574 void RenderWidget::paint(PaintInfo &paintInfo, int _tx, int _ty)
575 {
576 
577  // not visible or not even once layouted
578  if (style()->visibility() != VISIBLE || m_y <= -500000) {
579  return;
580  }
581 
582  _tx += m_x;
583  _ty += m_y;
584 
585  int os = maximalOutlineSize(paintInfo.phase);
586  if ((_ty - os > paintInfo.r.bottom()) || (_ty + m_height + os <= paintInfo.r.top()) ||
587  (_tx + m_width + os <= paintInfo.r.left()) || (_tx - os > paintInfo.r.right())) {
588  return;
589  }
590 
591  if ((paintInfo.phase == PaintActionChildBackground || paintInfo.phase == PaintActionChildBackgrounds) &&
592  shouldPaintBackgroundOrBorder() && !qobject_cast<KUrlRequester *>(m_widget)) {
593  paintBoxDecorations(paintInfo, _tx, _ty);
594  }
595 
596  if (paintInfo.phase == PaintActionOutline && style()->outlineWidth()) {
597  paintOutline(paintInfo.p, _tx, _ty, width(), height(), style());
598  }
599 
600  if (!m_widget || !m_view || paintInfo.phase != PaintActionForeground) {
601  return;
602  }
603 
604  int xPos = _tx + borderLeft() + paddingLeft();
605  int yPos = _ty + borderTop() + paddingTop();
606 
607  bool khtmlw = isRedirectedWidget();
608  int childw = m_widget->width();
609  int childh = m_widget->height();
610  if ((childw == 2000 || childh == 3072) && m_widget->inherits("KHTMLView")) {
611  KHTMLView *vw = static_cast<KHTMLView *>(m_widget);
612  int cy = m_view->contentsY();
613  int ch = m_view->visibleHeight();
614 
615  int childx = m_widget->pos().x();
616  int childy = m_widget->pos().y();
617 
618  int xNew = xPos;
619  int yNew = childy;
620 
621  // qDebug("cy=%d, ch=%d, childy=%d, childh=%d", cy, ch, childy, childh );
622  if (childh == 3072) {
623  if (cy + ch > childy + childh) {
624  yNew = cy + (ch - childh) / 2;
625  } else if (cy < childy) {
626  yNew = cy + (ch - childh) / 2;
627  }
628 // qDebug("calculated yNew=%d", yNew);
629  }
630  yNew = qMin(yNew, yPos + m_height - childh);
631  yNew = qMax(yNew, yPos);
632  if (yNew != childy || xNew != childx) {
633  if (vw->contentsHeight() < yNew - yPos + childh) {
634  vw->resizeContents(vw->contentsWidth(), yNew - yPos + childh);
635  }
636  vw->setContentsPos(xNew - xPos, yNew - yPos);
637  }
638  xPos = xNew;
639  yPos = yNew;
640  }
641  m_view->setWidgetVisible(this, true);
642  if (!khtmlw) {
643  m_view->addChild(m_widget, xPos, yPos);
644  } else {
645  m_view->addChild(m_widget, xPos, -500000 + yPos);
646  }
647  m_widget->show();
648  if (khtmlw) {
649  if (KHTMLView *v = qobject_cast<KHTMLView *>(m_widget)) {
650  // our buffers are dedicated to scrollbars.
651  if (v->verticalScrollBar()->isVisible() && (!m_buffer[0] || v->verticalScrollBar()->size() != m_buffer[0]->size())) {
652  delete m_buffer[0];
653  m_buffer[0] = new QPixmap(v->verticalScrollBar()->size());
654  }
655  if (v->horizontalScrollBar()->isVisible() && (!m_buffer[1] || v->horizontalScrollBar()->size() != m_buffer[1]->size())) {
656  delete m_buffer[1];
657  m_buffer[1] = new QPixmap(v->horizontalScrollBar()->size());
658  }
659  } else if (!m_buffer[0] || (m_widget->size() != m_buffer[0]->size())) {
660  assert(!m_buffer[1]);
661  delete m_buffer[0];
662  m_buffer[0] = new QPixmap(m_widget->size());
663  }
664  paintWidget(paintInfo, m_widget, xPos, yPos, m_buffer);
665  }
666 }
667 
668 static void setInPaintEventFlag(QWidget *w, bool b = true, bool recurse = true)
669 {
671 
672  if (!recurse) {
673  return;
674  }
675  if (qobject_cast<KHTMLView *>(w)) {
676  setInPaintEventFlag(static_cast<KHTMLView *>(w)->widget(), b, false);
677  setInPaintEventFlag(static_cast<KHTMLView *>(w)->horizontalScrollBar(), b, false);
678  setInPaintEventFlag(static_cast<KHTMLView *>(w)->verticalScrollBar(), b, false);
679  return;
680  }
681 
682  foreach (QObject *o, w->children()) {
683  QWidget *const cw = static_cast<QWidget *>(o);
684  if (o->isWidgetType() && ! cw->isWindow()
685  && !(cw->windowModality() & Qt::ApplicationModal)) {
686  setInPaintEventFlag(cw, b);
687  }
688  }
689 }
690 
691 static void copyWidget(const QRect &r, QPainter *p, QWidget *widget, int tx, int ty, bool buffered = false, QPixmap *buffer = nullptr)
692 {
693  if (r.isNull() || r.isEmpty()) {
694  return;
695  }
696 
697  QPoint thePoint(tx, ty);
698  QTransform t = p->worldTransform();
699 
700  if (!buffered && t.isTranslating()) {
701  thePoint.setX(thePoint.x() + static_cast<int>(t.dx()));
702  thePoint.setY(thePoint.y() + static_cast<int>(t.dy()));
703  }
704  QPixmap *pm = nullptr;
705  QPaintDevice *d = p->device();
706 #ifdef IN_PLACE_WIDGET_PAINTING
707  QPaintDevice *x = d;
708  bool vte = p->viewTransformEnabled();
709  bool wme = p->worldMatrixEnabled();
710  QRect w = p->window();
711  QRect v = p->viewport();
712  QRegion rg = p->clipRegion();
713  qreal op = p->opacity();
714  QPen pen = p->pen();
715  QBrush brush = p->brush();
717 #endif
718  if (buffered) {
719  if (!widget->size().isValid()) {
720  return;
721  }
722  // TT says Qt 4's widget painting hits an NVidia RenderAccel bug/shortcoming
723  // resulting in pixmap buffers being unsuitable for reuse by more than one widget.
724  //
725  // Until a turnaround exist in Qt, we can't reliably use shared buffers.
726  // ### pm = PaintBuffer::grab(widget->size());
727  assert(buffer);
728  pm = buffer;
729  if (!pm->hasAlphaChannel()) {
730  pm->fill(Qt::transparent);
731  } else {
732  QPainter pp(pm);
734  pp.fillRect(r, Qt::transparent);
735  }
736  d = pm;
737  } else {
738  p->end();
739  }
740 
741  setInPaintEventFlag(widget, false);
742 
743  widget->render(d, (buffered ? QPoint(0, 0) : thePoint) + r.topLeft(), r);
744 
745  setInPaintEventFlag(widget);
746 
747  if (!buffered) {
748 #ifdef IN_PLACE_WIDGET_PAINTING
749  p->begin(x);
750  p->setWorldTransform(t);
751  p->setWindow(w);
752  p->setViewport(v);
753  p->setViewTransformEnabled(vte);
754  p->setWorldMatrixEnabled(wme);
755  p->setRenderHints(rh);
756  if (!rg.isEmpty()) {
757  p->setClipRegion(rg);
758  }
759  if (op < 1.0f) {
760  p->setOpacity(op);
761  }
762  p->setPen(pen);
763  p->setBrush(brush);
764 #else
765  assert(false);
766 #endif
767  } else {
768  // transfer results
769  QPoint off(r.x(), r.y());
770  p->drawPixmap(thePoint + off, static_cast<QPixmap &>(*d), r);
771  // ### PaintBuffer::release(pm);
772  }
773 }
774 
775 void RenderWidget::paintWidget(PaintInfo &pI, QWidget *widget, int tx, int ty, QPixmap *buffer[])
776 {
777  QPainter *const p = pI.p;
778  allowWidgetPaintEvents = true;
779 
780  bool buffered =
781 #ifdef IN_PLACE_WIDGET_PAINTING
782  p->combinedMatrix().m22() != 1.0 || (p->device()->devType() == QInternal::Printer);
783 #else
784  true;
785 #endif
786  QRect rr = pI.r;
787  rr.translate(-tx, -ty);
788  const QRect r = widget->rect().intersected(rr);
789  if (KHTMLView *v = qobject_cast<KHTMLView *>(widget)) {
790  QPoint thePoint(tx, ty);
791  if (v->verticalScrollBar()->isVisible()) {
792  QRect vbr = v->verticalScrollBar()->rect();
793  QPoint of = v->verticalScrollBar()->mapTo(v, QPoint(vbr.x(), vbr.y()));
794  vbr.translate(of);
795  vbr &= r;
796  vbr.translate(-of);
797  if (vbr.isValid() && !vbr.isEmpty()) {
798  copyWidget(vbr, p, v->verticalScrollBar(), tx + of.x(), ty + of.y(), buffered, buffer[0]);
799  }
800  }
801  if (v->horizontalScrollBar()->isVisible()) {
802  QRect hbr = v->horizontalScrollBar()->rect();
803  QPoint of = v->horizontalScrollBar()->mapTo(v, QPoint(hbr.x(), hbr.y()));
804  hbr.translate(of);
805  hbr &= r;
806  hbr.translate(-of);
807  if (hbr.isValid() && !hbr.isEmpty()) {
808  copyWidget(hbr, p, v->horizontalScrollBar(), tx + of.x(), ty + of.y(), buffered, buffer[1]);
809  }
810  }
811  QPoint of = v->viewport()->mapTo(v, QPoint(0, 0));
812  QRect vr = (r & v->viewport()->rect().translated(of));
813  if (vr.isValid() && !vr.isEmpty()) {
814  v->render(p, vr, thePoint);
815  }
816  } else {
817  copyWidget(r, p, widget, tx, ty, buffered, buffer[0]);
818  }
819  allowWidgetPaintEvents = false;
820 }
821 
822 bool RenderWidget::eventFilter(QObject * /*o*/, QEvent *e)
823 {
824  // no special event processing if this is a frame (in which case KHTMLView handles it all)
825  if (qobject_cast<KHTMLView *>(m_widget) || isRedirectedWidget()) {
826  return false;
827  }
828  if (!element()) {
829  return true;
830  }
831 
832  static bool directToWidget = false;
833  if (directToWidget) {
834  //We're trying to get the event to the widget
835  //promptly. So get out of here..
836  return false;
837  }
838 
839  ref();
840  element()->ref();
841 
842  bool filtered = false;
843 
844  //qCDebug(KHTML_LOG) << "RenderWidget::eventFilter type=" << e->type();
845  switch (e->type()) {
846  case QEvent::FocusOut:
847  // First, forward it to the widget, so that Qt gets a precise
848  // state of the focus before pesky JS can try changing it..
849  directToWidget = true;
850  QApplication::sendEvent(m_widget, e);
851  directToWidget = false;
852  filtered = true; //We already delivered it!
853 
854  // Don't count popup as a valid reason for losing the focus
855  // (example: opening the options of a select combobox shouldn't emit onblur)
856  if (static_cast<QFocusEvent *>(e)->reason() != Qt::PopupFocusReason) {
857  handleFocusOut();
858  }
859  break;
860  case QEvent::FocusIn:
861  //As above, forward to the widget first...
862  directToWidget = true;
863  QApplication::sendEvent(m_widget, e);
864  directToWidget = false;
865  filtered = true; //We already delivered it!
866 
867  //qCDebug(KHTML_LOG) << "RenderWidget::eventFilter captures FocusIn";
868  document()->setFocusNode(element());
869 // if ( isEditable() ) {
870 // KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>( element()->view->part()->browserExtension() );
871 // if ( ext ) ext->editableWidgetFocused( m_widget );
872 // }
873  break;
874  case QEvent::Wheel: {
875  if (widget()->parentWidget() == view()->widget()) {
876  bool vertical = (static_cast<QWheelEvent *>(e)->orientation() == Qt::Vertical);
877  // don't allow the widget to react to wheel event if
878  // the view is being scrolled by mouse wheel
879  // This does not apply if the webpage has no valid scroll range in the given wheel event orientation.
880  if (((vertical && (view()->contentsHeight() > view()->visibleHeight())) ||
881  (!vertical && (view()->contentsWidth() > view()->visibleWidth()))) &&
882  view()->isScrollingFromMouseWheel()) {
883  static_cast<QWheelEvent *>(e)->ignore();
884  QApplication::sendEvent(view(), e);
885  filtered = true;
886  }
887  }
888  break;
889  }
890  case QEvent::KeyPress:
891  case QEvent::KeyRelease:
892  // TODO this seems wrong - Qt events are not correctly translated to DOM ones,
893  // like in KHTMLView::dispatchKeyEvent()
894  if (element()->dispatchKeyEvent(static_cast<QKeyEvent *>(e), false)) {
895  filtered = true;
896  }
897  break;
898 
899  default:
900  break;
901  };
902 
903  element()->deref();
904 
905  // stop processing if the widget gets deleted, but continue in all other cases
906  if (hasOneRef()) {
907  filtered = true;
908  }
909  deref();
910 
911  return filtered;
912 }
913 
914 void RenderWidget::EventPropagator::sendEvent(QEvent *e)
915 {
916  // ### why don't we just call event()? That would be the normal route.
917  switch (e->type()) {
918  case QEvent::Wheel:
919  wheelEvent(static_cast<QWheelEvent *>(e));
920  break;
922  mousePressEvent(static_cast<QMouseEvent *>(e));
923  break;
925  mouseReleaseEvent(static_cast<QMouseEvent *>(e));
926  break;
928  mouseDoubleClickEvent(static_cast<QMouseEvent *>(e));
929  break;
930  case QEvent::MouseMove:
931  mouseMoveEvent(static_cast<QMouseEvent *>(e));
932  break;
933  case QEvent::KeyPress:
934  keyPressEvent(static_cast<QKeyEvent *>(e));
935  break;
936  case QEvent::KeyRelease:
937  if (qobject_cast<QLineEdit *>(this)) {
938  event(e);
939  } else {
940  keyReleaseEvent(static_cast<QKeyEvent *>(e));
941  }
942  break;
943  case QEvent::FocusIn:
944  focusInEvent(static_cast<QFocusEvent *>(e));
945  break;
946  case QEvent::FocusOut:
947  focusOutEvent(static_cast<QFocusEvent *>(e));
948  break;
949  case QEvent::ContextMenu:
950  contextMenuEvent(static_cast<QContextMenuEvent *>(e));
951  break;
952  default:
953  break;
954  }
955 }
956 
957 // send event to target and let it bubble up until it is accepted or
958 // once it would go through a limiting widget level
959 static bool bubblingSend(QWidget *target, QEvent *e, QWidget *stoppingParent)
960 {
961  for (;;) {
962  static_cast<RenderWidget::EventPropagator *>(target)->sendEvent(e);
963  if (e->isAccepted()) {
964  return true;
965  }
966  if (target == stoppingParent) {
967  return false;
968  }
969  // ### might want to shift Q*Event::pos() as we go up
970  target = target->parentWidget();
971  assert(target != nullptr);
972  }
973 }
974 
975 bool RenderWidget::handleEvent(const DOM::EventImpl &ev)
976 {
977  bool ret = false;
978 
979  switch (ev.id()) {
980  case EventImpl::DOMFOCUSIN_EVENT:
981  case EventImpl::DOMFOCUSOUT_EVENT: {
982  QFocusEvent e(ev.id() == EventImpl::DOMFOCUSIN_EVENT ? QEvent::FocusIn : QEvent::FocusOut);
983  // E.g. a KLineEdit child widget might be defined to receive
984  // focus instead
985  QWidget *fw = m_widget->focusProxy() ? m_widget->focusProxy() : m_widget;
986  static_cast<EventPropagator *>(fw)->sendEvent(&e);
987  ret = e.isAccepted();
988  break;
989  }
990  case EventImpl::KHTML_MOUSEWHEEL_EVENT:
991  case EventImpl::MOUSEDOWN_EVENT:
992  case EventImpl::MOUSEUP_EVENT:
993  case EventImpl::MOUSEMOVE_EVENT: {
994  if (!ev.isMouseEvent()) {
995  break;
996  }
997 
998  const MouseEventImpl &me = static_cast<const MouseEventImpl &>(ev);
999  QMouseEvent *const qme = me.qEvent();
1000  QMouseEvent::Type type;
1001  Qt::MouseButton button = Qt::NoButton;
1002  Qt::MouseButtons buttons = Qt::NoButton;
1004  Qt::Orientation orient = Qt::Vertical;
1005 
1006  if (qme) {
1007  buttons = qme->buttons();
1008  button = qme->button();
1009  state = qme->modifiers();
1010  type = qme->type();
1011  } else {
1012  switch (me.button()) {
1013  case 0:
1014  button = Qt::LeftButton;
1015  break;
1016  case 1:
1017  button = Qt::MidButton;
1018  break;
1019  case 2:
1020  button = Qt::RightButton;
1021  break;
1022  default:
1023  break;
1024  }
1025 
1026  buttons = button;
1027 
1028  switch (me.id()) {
1029  case EventImpl::MOUSEDOWN_EVENT:
1031  break;
1032  case EventImpl::MOUSEUP_EVENT:
1034  break;
1035  case EventImpl::KHTML_MOUSEWHEEL_EVENT:
1036  case EventImpl::MOUSEMOVE_EVENT:
1037  default:
1038  type = QMouseEvent::MouseMove;
1039  button = Qt::NoButton;
1040  break;
1041  }
1042 
1043  if (me.orientation() == MouseEventImpl::OHorizontal) {
1044  orient = Qt::Horizontal;
1045  }
1046 
1047  if (me.ctrlKey()) {
1048  state |= Qt::ControlModifier;
1049  }
1050  if (me.altKey()) {
1051  state |= Qt::AltModifier;
1052  }
1053  if (me.shiftKey()) {
1054  state |= Qt::ShiftModifier;
1055  }
1056  if (me.metaKey()) {
1057  state |= Qt::MetaModifier;
1058  }
1059  }
1060 
1061  int absx = 0;
1062  int absy = 0;
1063  absolutePosition(absx, absy);
1064  absx += borderLeft() + paddingLeft();
1065  absy += borderTop() + paddingTop();
1066 
1067  QPoint p(me.clientX() - absx + m_view->contentsX(),
1068  me.clientY() - absy + m_view->contentsY());
1069 
1070  if (ev.id() == EventImpl::MOUSEMOVE_EVENT && view()->mouseEventsTarget()) {
1071  // mitigate the problem that mouse moves outside of the widget rect
1072  // interrupt the selection process in textarea (#156574)
1073  // e.g. when extending a selection upward to make a textarea scroll
1074  // while selecting its content.
1075  // We don't emulate properly what Qt does it seems,tough I verified
1076  // the move event is properly forwarded to the textarea and has
1077  // appropriate coordinates. Might be Enter/Leave issue. ### FIXME
1078  // In the meantime, clamping the event to the widget rect
1079  // will at least prevent the selection to be lost.
1080  p.setX(qMin(qMax(0, p.x()), m_widget->width()));
1081  p.setY(qMin(qMax(0, p.y()), m_widget->height()));
1082  }
1083 
1084  QPointer<QWidget> target;
1085  target = m_widget->childAt(p);
1086 
1087  if (target) {
1088  p = target->mapFrom(m_widget, p);
1089  }
1090 
1091  if (m_underMouse != target && ev.id() != EventImpl::KHTML_MOUSEWHEEL_EVENT) {
1092  if (m_underMouse) {
1093  QEvent moe(QEvent::Leave);
1094  QApplication::sendEvent(m_underMouse, &moe);
1095 // qCDebug(KHTML_LOG) << "sending LEAVE to"<< m_underMouse;
1096  if (m_underMouse->testAttribute(Qt::WA_Hover)) {
1097  QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), QPoint(0, 0));
1098  QApplication::sendEvent(m_underMouse, &he);
1099  }
1100  }
1101  if (target) {
1102  QEvent moe(QEvent::Enter);
1103  QApplication::sendEvent(target, &moe);
1104 // qCDebug(KHTML_LOG) << "sending ENTER to" << target;
1105  if (target->testAttribute(Qt::WA_Hover)) {
1106  QHoverEvent he(QEvent::HoverEnter, QPoint(0, 0), QPoint(-1, -1));
1107  QApplication::sendEvent(target, &he);
1108  }
1109  }
1110  m_underMouse = target;
1111  }
1112 #if 0
1113  if (target && ev.id() == EventImpl::MOUSEMOVE_EVENT) {
1114  // ### is this one still necessary? it doubles every mouse event...
1115  // I'd reckon it's no longer needed since Harri made the event propagation bubble
1118  QApplication::sendEvent(target, &evt);
1119  }
1120 #endif
1121  if (ev.id() == EventImpl::MOUSEDOWN_EVENT) {
1122  if (!target || (!::qobject_cast<QScrollBar *>(target) &&
1123  !::qobject_cast<KUrlRequester *>(m_widget) &&
1124  !::qobject_cast<QLineEdit *>(m_widget))) {
1125  target = m_widget;
1126  }
1127  view()->setMouseEventsTarget(target);
1128  } else {
1129  target = view()->mouseEventsTarget();
1130  if (target) {
1131  QWidget *parent = target;
1132  while (parent && parent != m_widget) {
1133  parent = parent->parentWidget();
1134  }
1135  if (!parent) {
1136  return false;
1137  }
1138  } else {
1139  target = m_widget;
1140  }
1141  }
1142 
1143  bool needContextMenuEvent = (type == QMouseEvent::MouseButtonPress && button == Qt::RightButton);
1144  bool isMouseWheel = (ev.id() == EventImpl::KHTML_MOUSEWHEEL_EVENT);
1145 
1146  if (isMouseWheel) {
1147  // don't allow the widget to react to wheel event if
1148  // a) the view is being scrolled by mouse wheel
1149  // b) it's an unfocused ComboBox (for extra security against unwanted changes to formulars)
1150  // This does not apply if the webpage has no valid scroll range in the given wheel event orientation.
1151  if (((orient == Qt::Vertical && (view()->contentsHeight() > view()->visibleHeight())) ||
1152  (orient == Qt::Horizontal && (view()->contentsWidth() > view()->visibleWidth()))) &&
1153  (view()->isScrollingFromMouseWheel() ||
1154  (qobject_cast<QComboBox *>(m_widget) &&
1155  (!document()->focusNode() || document()->focusNode()->renderer() != this)))) {
1156  ret = false;
1157  break;
1158  }
1159  }
1160 
1161  QScopedPointer<QEvent> e(isMouseWheel ?
1162  static_cast<QEvent *>(new QWheelEvent(p, -me.detail() * 40, buttons, state, orient)) :
1163  static_cast<QEvent *>(new QMouseEvent(type, p, button, buttons, state)));
1164 
1165  ret = bubblingSend(target, e.data(), m_widget);
1166 
1167  if (!target) {
1168  break;
1169  }
1170  if (needContextMenuEvent) {
1172  static_cast<EventPropagator *>(target.data())->sendEvent(&cme);
1173  } else if (type == QEvent::MouseMove && target->testAttribute(Qt::WA_Hover)) {
1174  QHoverEvent he(QEvent::HoverMove, p, p);
1175  QApplication::sendEvent(target, &he);
1176  }
1177  if (ev.id() == EventImpl::MOUSEUP_EVENT) {
1178  view()->setMouseEventsTarget(nullptr);
1179  }
1180  break;
1181  }
1182  case EventImpl::KEYDOWN_EVENT:
1183  // do nothing; see the mapping table below
1184  break;
1185  case EventImpl::KEYUP_EVENT: {
1186  if (!ev.isKeyRelatedEvent()) {
1187  break;
1188  }
1189 
1190  const KeyEventBaseImpl &domKeyEv = static_cast<const KeyEventBaseImpl &>(ev);
1191  if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) {
1192  break;
1193  }
1194 
1195  QKeyEvent *const ke = domKeyEv.qKeyEvent();
1196  static_cast<EventPropagator *>(m_widget)->sendEvent(ke);
1197  ret = ke->isAccepted();
1198  break;
1199  }
1200  case EventImpl::KEYPRESS_EVENT: {
1201  if (!ev.isKeyRelatedEvent()) {
1202  break;
1203  }
1204 
1205  const KeyEventBaseImpl &domKeyEv = static_cast<const KeyEventBaseImpl &>(ev);
1206  if (domKeyEv.isSynthetic() && !acceptsSyntheticEvents()) {
1207  break;
1208  }
1209 
1210  // See KHTMLView::dispatchKeyEvent: autorepeat is just keypress in the DOM
1211  // but it's keyrelease+keypress in Qt. So here we do the inverse mapping as
1212  // the one done in KHTMLView: generate two events for one DOM auto-repeat keypress.
1213  // Similarly, DOM keypress events with non-autorepeat Qt event do nothing here,
1214  // because the matching Qt keypress event was already sent from DOM keydown event.
1215 
1216  // Reverse drawing as the one in KHTMLView:
1217  // DOM: Down Press | Press | Up
1218  // Qt: (nothing) Press | Release(autorepeat) + Press(autorepeat) | Release
1219  //
1220  // Qt::KeyPress is sent for DOM keypress and not DOM keydown to allow
1221  // sites to block a key with onkeypress, #99749
1222 
1223  QKeyEvent *const ke = domKeyEv.qKeyEvent();
1224  if (ke->isAutoRepeat()) {
1225  QKeyEvent releaseEv(QEvent::KeyRelease, ke->key(), ke->modifiers(),
1226  ke->text(), ke->isAutoRepeat(), ke->count());
1227  static_cast<EventPropagator *>(m_widget)->sendEvent(&releaseEv);
1228  }
1229  QWidget *fw = m_widget->focusWidget() ? m_widget->focusWidget() : m_widget;
1230  static_cast<EventPropagator *>(fw)->sendEvent(ke);
1231  ret = ke->isAccepted();
1232  break;
1233  }
1234  case EventImpl::MOUSEOUT_EVENT: {
1235  QWidget *target = m_underMouse ? (QWidget *) m_underMouse : m_widget;
1236  QEvent moe(QEvent::Leave);
1237  QApplication::sendEvent(target, &moe);
1238 // qCDebug(KHTML_LOG) << "received MOUSEOUT, forwarding to" << target ;
1239  if (target->testAttribute(Qt::WA_Hover)) {
1240  QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), QPoint(0, 0));
1241  QApplication::sendEvent(target, &he);
1242  }
1243  m_underMouse = nullptr;
1244  break;
1245  }
1246  case EventImpl::MOUSEOVER_EVENT: {
1247  QEvent moe(QEvent::Enter);
1248  QApplication::sendEvent(m_widget, &moe);
1249 // qCDebug(KHTML_LOG) << "received MOUSEOVER, forwarding to" << m_widget;
1250  if (m_widget->testAttribute(Qt::WA_Hover)) {
1251  QHoverEvent he(QEvent::HoverEnter, QPoint(0, 0), QPoint(-1, -1));
1252  QApplication::sendEvent(m_widget, &he);
1253  }
1254  view()->part()->resetHoverText();
1255  break;
1256  }
1257  default:
1258  break;
1259  }
1260  return ret;
1261 }
1262 
1263 void RenderWidget::deref()
1264 {
1265  if (_ref) {
1266  _ref--;
1267  }
1268 // qDebug( "deref(%p): width get count is %d", this, _ref);
1269  if (!_ref) {
1270  if (attached()) {
1271  _ref++;
1272  detach(); // will perform the final deref.
1273  return;
1274  }
1275  SharedPtr<RenderArena> guard(m_arena); //Since delete on us gets called -first-,
1276  //before the arena free
1277  arenaDelete(m_arena.get());
1278  }
1279 }
1280 
1281 #ifdef ENABLE_DUMP
1282 void RenderWidget::dump(QTextStream &stream, const QString &ind) const
1283 {
1284  RenderReplaced::dump(stream, ind);
1285  if (widget())
1286  stream << " color=" << widget()->palette().color(widget()->foregroundRole()).name()
1287  << " bg=" << widget()->palette().color(widget()->backgroundRole()).name();
1288  else {
1289  stream << " null widget";
1290  }
1291 }
1292 #endif
1293 
1294 // -----------------------------------------------------------------------------
1295 
1296 QPoint KHTMLWidgetPrivate::absolutePos()
1297 {
1298  if (!m_rw) {
1299  return m_pos;
1300  }
1301  int x, y;
1302  m_rw->absolutePosition(x, y);
1303  x += m_rw->borderLeft() + m_rw->paddingLeft();
1304  y += m_rw->borderTop() + m_rw->paddingTop();
1305  return QPoint(x, y);
1306 }
1307 
1308 KHTMLView *KHTMLWidgetPrivate::rootViewPos(QPoint &pos)
1309 {
1310  if (!m_rw || !m_rw->widget()) {
1311  pos = QPoint();
1312  return nullptr;
1313  }
1314  pos = absolutePos();
1315  KHTMLView *v = m_rw->view();
1316  KHTMLView *last = nullptr;
1317  while (v) {
1318  last = v;
1319  int w, h = 0;
1320  v->applyTransforms(pos.rx(), pos.ry(), w, h);
1321  KHTMLWidget *kw = dynamic_cast<KHTMLWidget *>(v);
1322  if (!kw || !kw->m_kwp->isRedirected()) {
1323  break;
1324  }
1325  pos += kw->m_kwp->absolutePos();
1326  v = v->part()->parentPart() ? v->part()->parentPart()->view() : nullptr;
1327  }
1328  return last;
1329 }
1330 
1331 void KHTMLWidgetPrivate::setIsRedirected(bool b)
1332 {
1333  m_redirected = b;
1334  if (!b && m_rw && m_rw->widget()) {
1335  setInPaintEventFlag(m_rw->widget(), false);
1336  m_rw->widget()->setAttribute(Qt::WA_OpaquePaintEvent, false);
1337  m_rw->widget()->removeEventFilter(m_rw->view());
1338  }
1339 }
1340 
1341 // -----------------------------------------------------------------------------
1342 
1343 KHTMLWidget::KHTMLWidget()
1344  : m_kwp(new KHTMLWidgetPrivate()) {}
1345 
1346 KHTMLWidget::~KHTMLWidget()
1347 {
1348  delete m_kwp;
1349 }
1350 
void setOpacity(qreal opacity)
typedef KeyboardModifiers
Qt::KeyboardModifiers modifiers() const const
void setViewport(const QRect &rectangle)
StrongFocus
QEvent::Type type() const const
void setPalette(const QPalette &)
int & rx()
int & ry()
QColor darker(int factor) const const
T * data() const const
static int contrast()
bool end()
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setCompositionMode(QPainter::CompositionMode mode)
void fill(const QColor &color)
void setColor(QPalette::ColorGroup group, QPalette::ColorRole role, const QColor &color)
qreal dx() const const
qreal dy() const const
QRect window() const const
QPainter::RenderHints renderHints() const const
int count() 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
QMatrix combinedMatrix() const const
const QColor & color(QPalette::ColorGroup group, QPalette::ColorRole role) const const
const QObjectList & children() const const
void translate(int dx, int dy)
MouseButton
void setAttribute(Qt::WidgetAttribute attribute, bool on)
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
int height() const const
int x() const const
int y() const const
void setClipRegion(const QRegion &region, Qt::ClipOperation operation)
PopupFocusReason
Qt::MouseButtons buttons() const const
bool isAutoRepeat() const const
void setContentsPos(int x, int y)
Place the contents area point x/y at the top left of the viewport.
Definition: khtmlview.cpp:751
bool hasAlphaChannel() const const
Qt::KeyboardModifiers keyboardModifiers()
QWidget * focusWidget() const const
void setParent(QWidget *parent)
void getHsv(int *h, int *s, int *v, int *a) const const
int x() const const
int y() const const
virtual bool event(QEvent *e)
bool viewTransformEnabled() const const
KHTMLView * view() const
Returns a pointer to the HTML document&#39;s view.
KHTMLPart * part() const
Returns a pointer to the KHTMLPart that is rendering the page.
Definition: khtmlview.h:139
bool allowWidgetPaintEvents
This file is part of the HTML widget for KDE.
qreal m22() const const
void setWindow(const QRect &rectangle)
bool testAttribute(Qt::WidgetAttribute attribute) const const
bool isAccepted() const const
QRegion clipRegion() const const
void setPen(const QColor &color)
void setWorldTransform(const QTransform &matrix, bool combine)
QPalette palette()
int contentsHeight() const
Returns the contents area&#39;s height.
Definition: khtmlview.cpp:693
Qt::MouseButton button() const const
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
Qt::MouseButtons mouseButtons()
bool sendEvent(QObject *receiver, QEvent *event)
QString text() const const
QPaintDevice * device() const const
void setBrush(const QBrush &brush)
QRect translated(int dx, int dy) const const
QRect intersected(const QRect &rectangle) const const
const QTransform & worldTransform() const const
bool isWindow() const const
Qt::KeyboardModifiers modifiers() const const
T * data() const const
int key() const const
CompositionMode_Source
const QBrush & brush() const const
bool isEmpty() const const
QColor lighter(int factor) const const
bool isValid() const const
QRect viewport() const const
void setRenderHints(QPainter::RenderHints hints, bool on)
WA_NoSystemBackground
bool isNull() const const
This library provides a full-featured HTML parser and widget.
int width() const const
QWidget * parentWidget() const const
void setWorldMatrixEnabled(bool enable)
bool worldMatrixEnabled() const const
QPoint topLeft() const const
void setX(int x)
void setY(int y)
QWidget * focusProxy() const const
bool isEmpty() const const
Vertical
int contentsWidth() const
Returns the contents area&#39;s width.
Definition: khtmlview.cpp:688
void setViewTransformEnabled(bool enable)
bool isWidgetType() const const
ApplicationModal
transparent
typedef RenderHints
bool begin(QPaintDevice *device)
const QPen & pen() const const
virtual void resizeContents(int w, int h)
Resize the contents area.
Definition: khtmlview.cpp:698
qreal opacity() const const
void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, QWidget::RenderFlags renderFlags)
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
bool isTranslating() const const
bool isValid() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:48:00 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.