File indexing completed on 2024-11-10 09:39:04

0001 /**
0002 * This file is part of the HTML widget for KDE.
0003 *
0004 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
0005 *           (C) 2000-2003 Dirk Mueller (mueller@kde.org)
0006 *           (C) 2003 Apple Computer, Inc.
0007 *           (C) 2004-2006 Germain Garand (germain@ebooksfrance.org)
0008 *
0009 * This library is free software; you can redistribute it and/or
0010 * modify it under the terms of the GNU Library General Public
0011 * License as published by the Free Software Foundation; either
0012 * version 2 of the License, or (at your option) any later version.
0013 *
0014 * This library is distributed in the hope that it will be useful,
0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017 * Library General Public License for more details.
0018 *
0019 * You should have received a copy of the GNU Library General Public License
0020 * along with this library; see the file COPYING.LIB.  If not, write to
0021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022 * Boston, MA 02110-1301, USA.
0023 *
0024 */
0025 #include "render_replaced.h"
0026 #include "render_layer.h"
0027 #include "render_canvas.h"
0028 #include "render_line.h"
0029 #include "rendering/render_position.h"
0030 
0031 #include "render_arena.h"
0032 
0033 #include <assert.h>
0034 #include <QWidget>
0035 #include <QPainter>
0036 #include <QActionEvent>
0037 #include <QApplication>
0038 #include <QLineEdit>
0039 #include <QComboBox>
0040 #include <QCheckBox>
0041 #include <QRadioButton>
0042 #include <kurlrequester.h>
0043 #include <QVector>
0044 #include <QMatrix>
0045 #include <QPaintEngine>
0046 
0047 #include "khtml_ext.h"
0048 #include "khtmlview.h"
0049 #include "xml/dom2_eventsimpl.h"
0050 #include "khtml_part.h"
0051 #include "xml/dom_docimpl.h"
0052 #include "xml/dom_position.h"
0053 #include "misc/helper.h"
0054 #include "misc/paintbuffer.h"
0055 #include "css/cssvalues.h"
0056 
0057 #include <kcolorscheme.h>
0058 #include "khtml_debug.h"
0059 
0060 //#define IN_PLACE_WIDGET_PAINTING
0061 
0062 bool khtml::allowWidgetPaintEvents = false;
0063 
0064 using namespace khtml;
0065 using namespace DOM;
0066 
0067 RenderReplaced::RenderReplaced(DOM::NodeImpl *node)
0068     : RenderBox(node)
0069 {
0070     // init RenderObject attributes
0071     setReplaced(true);
0072 
0073     m_intrinsicWidth = 300;
0074     m_intrinsicHeight = 150;
0075 }
0076 
0077 void RenderReplaced::calcMinMaxWidth()
0078 {
0079     KHTMLAssert(!minMaxKnown());
0080 
0081 #ifdef DEBUG_LAYOUT
0082     // qCDebug(KHTML_LOG) << "RenderReplaced::calcMinMaxWidth() known=" << minMaxKnown();
0083 #endif
0084 
0085     m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
0086 
0087     if (style()->width().isPercent() || style()->height().isPercent() ||
0088             style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
0089             style()->minWidth().isPercent() || style()->minHeight().isPercent()) {
0090         m_minWidth = 0;
0091         m_maxWidth = m_width;
0092     } else {
0093         m_minWidth = m_maxWidth = m_width;
0094     }
0095 
0096     setMinMaxKnown();
0097 }
0098 
0099 FindSelectionResult RenderReplaced::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl *&node, int &offset, SelPointState &)
0100 {
0101 #if 0
0102     // qCDebug(KHTML_LOG) << "RenderReplaced::checkSelectionPoint(_x="<<_x<<",_y="<<_y<<",_tx="<<_tx<<",_ty="<<_ty<<")" << endl
0103             << "xPos: " << xPos() << " yPos: " << yPos() << " width: " << width() << " height: " << height() << endl
0104             << "_ty + yPos: " << (_ty + yPos()) << " + height: " << (_ty + yPos() + height()) << "; _tx + xPos: " << (_tx + xPos()) << " + width: " << (_tx + xPos() + width());
0105 #endif
0106     node = element();
0107     offset = 0;
0108 
0109     if (_y < _ty + yPos()) {
0110         return SelectionPointBefore;    // above -> before
0111     }
0112 
0113     if (_y > _ty + yPos() + height()) {
0114         // below -> after
0115         // Set the offset to the max
0116         offset = 1;
0117         return SelectionPointAfter;
0118     }
0119     if (_x > _tx + xPos() + width()) {
0120         // to the right
0121         // ### how to regard bidi in replaced elements? (LS)
0122         offset = 1;
0123         return SelectionPointAfterInLine;
0124     }
0125 
0126     // The Y matches, check if we're on the left
0127     if (_x < _tx + xPos()) {
0128         // ### how to regard bidi in replaced elements? (LS)
0129         return SelectionPointBeforeInLine;
0130     }
0131 
0132     offset = _x > _tx + xPos() + width() / 2;
0133     return SelectionPointInside;
0134 }
0135 
0136 long RenderReplaced::caretMinOffset() const
0137 {
0138     return 0;
0139 }
0140 
0141 // Returns 1 since a replaced element can have the caret positioned
0142 // at its beginning (0), or at its end (1).
0143 long RenderReplaced::caretMaxOffset() const
0144 {
0145     return 1;
0146 }
0147 
0148 unsigned long RenderReplaced::caretMaxRenderedOffset() const
0149 {
0150     return 1;
0151 }
0152 
0153 RenderPosition RenderReplaced::positionForCoordinates(int _x, int _y)
0154 {
0155     InlineBox *box = placeHolderBox();
0156     if (!box) {
0157         return RenderPosition(element(), 0);
0158     }
0159 
0160     RootInlineBox *root = box->root();
0161 
0162     int absx, absy;
0163     containingBlock()->absolutePosition(absx, absy);
0164 
0165     int top = absy + root->topOverflow();
0166     int bottom = root->nextRootBox() ? absy + root->nextRootBox()->topOverflow() : absy + root->bottomOverflow();
0167 
0168     if (_y < top) {
0169         return RenderPosition(element(), caretMinOffset());    // coordinates are above
0170     }
0171 
0172     if (_y >= bottom) {
0173         return RenderPosition(element(), caretMaxOffset());    // coordinates are below
0174     }
0175 
0176     if (element()) {
0177         if (_x <= absx + xPos() + (width() / 2)) {
0178             return RenderPosition(element(), 0);
0179         }
0180         return RenderPosition(element(), 1);
0181     }
0182 
0183     return RenderBox::positionForCoordinates(_x, _y);
0184 }
0185 
0186 // -----------------------------------------------------------------------------
0187 
0188 RenderWidget::RenderWidget(DOM::NodeImpl *node)
0189     : RenderReplaced(node)
0190 {
0191     m_widget = nullptr;
0192     m_underMouse = nullptr;
0193     m_buffer[0] = nullptr;
0194     m_buffer[1] = nullptr;
0195     m_nativeFrameShape = QFrame::NoFrame;
0196     // a widget doesn't support being anonymous
0197     assert(!isAnonymous());
0198     m_view  = node->document()->view();
0199     m_arena.reset(renderArena());
0200     m_needsMask = false;
0201     m_ownsWidget = true;
0202 
0203     // this is no real reference counting, it is just there
0204     // to make sure that we're not deleted while we're recursed
0205     // in an eventFilter of the widget
0206     ref();
0207 }
0208 
0209 void RenderWidget::detach()
0210 {
0211     // warning: keep in sync with RenderObject::detach
0212 
0213     detachCounters();
0214     remove();
0215 
0216     if (m_widget) {
0217         if (m_view) {
0218             m_view->setWidgetVisible(this, false);
0219         }
0220         KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget);
0221         if (k) {
0222             k->m_kwp->setRenderWidget(nullptr);
0223         }
0224         m_widget->removeEventFilter(this);
0225         m_widget->setMouseTracking(false);
0226     }
0227 
0228     // make sure our DOM-node don't think we exist
0229     if (node() && node()->renderer() == this) {
0230         node()->setRenderer(nullptr);
0231     }
0232 
0233     setDetached();
0234     deref();
0235 }
0236 
0237 RenderWidget::~RenderWidget()
0238 {
0239     KHTMLAssert(refCount() <= 0);
0240 
0241     if (m_widget) {
0242         if (m_widget->hasFocus()) {
0243             m_widget->clearFocus();
0244         }
0245         m_widget->hide();
0246         if (m_ownsWidget) {
0247             m_widget->deleteLater();
0248         }
0249     }
0250     delete m_buffer[0];
0251     delete m_buffer[1];
0252 }
0253 
0254 class QWidgetResizeEvent : public QEvent
0255 {
0256 public:
0257     enum { Type = QEvent::User + 0xbee };
0258     QWidgetResizeEvent(int _w,  int _h) :
0259         QEvent((QEvent::Type) Type),  w(_w), h(_h) {}
0260     int w;
0261     int h;
0262 };
0263 
0264 void  RenderWidget::resizeWidget(int w, int h)
0265 {
0266     // ugly hack to limit the maximum size of the widget ( as X11 has problems if
0267     // it is bigger )
0268     h = qMin(h, 3072);
0269     w = qMin(w, 2000);
0270 
0271     if (m_widget->width() != w || m_widget->height() != h) {
0272         m_widget->resize(w, h);
0273         if (isRedirectedWidget() && qobject_cast<KHTMLView *>(m_widget) && !m_widget->isVisible()) {
0274             // Emission of Resize event is delayed.
0275             // we have to pre-call KHTMLView::resizeEvent
0276             // so that viewport size change and subsequent layout update
0277             // is effective synchronously, which is important for JS.
0278             // This only work because m_widget is a redirected view,
0279             // and thus has visibleWidth()/visibleHeight() that mirror this RenderWidget,
0280             // rather than the effective widget size. - gg.
0281             QResizeEvent e(QSize(w, h), QSize(m_widget->width(), m_widget->height()));
0282             static_cast<KHTMLView *>(m_widget)->resizeEvent(&e);
0283         }
0284     }
0285 }
0286 
0287 bool RenderWidget::event(QEvent *e)
0288 {
0289     // eat all events - except if this is a frame (in which case KHTMLView handles it all)
0290     if (qobject_cast<KHTMLView *>(m_widget)) {
0291         return QObject::event(e);
0292     }
0293     return true;
0294 }
0295 
0296 bool RenderWidget::isRedirectedWidget() const
0297 {
0298     KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget);
0299     return k ? k->m_kwp->isRedirected() : false;
0300 }
0301 
0302 void RenderWidget::setQWidget(QWidget *widget)
0303 {
0304     if (widget != m_widget) {
0305         if (m_widget) {
0306             m_widget->removeEventFilter(this);
0307             disconnect(m_widget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestructed()));
0308             m_widget->hide();
0309             if (m_ownsWidget) {
0310                 m_widget->deleteLater();    //Might happen due to event on the widget, so be careful
0311             }
0312             m_widget = nullptr;
0313         }
0314         m_widget = widget;
0315         if (m_widget) {
0316             KHTMLWidget *k = dynamic_cast<KHTMLWidget *>(m_widget);
0317             bool isRedirectedSubFrame = false;
0318             if (k) {
0319                 k->m_kwp->setRenderWidget(this);
0320                 // enable redirection of every sub-frame that is not a FRAME
0321                 if (qobject_cast<KHTMLView *>(m_widget) && element() && element()->id() != ID_FRAME) {
0322                     k->m_kwp->setIsRedirected(true);
0323                     isRedirectedSubFrame = true;
0324                 }
0325             }
0326             m_widget->setParent(m_view->widget());
0327             if (isRedirectedSubFrame) {
0328                 static_cast<KHTMLView *>(m_widget)->setHasStaticBackground();
0329             }
0330             connect(m_widget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestructed()));
0331             m_widget->installEventFilter(this);
0332             if (isRedirectedWidget()) {
0333                 if (!qobject_cast<QFrame *>(m_widget)) {
0334                     m_widget->setAttribute(Qt::WA_NoSystemBackground);
0335                 }
0336             }
0337             if (m_widget->focusPolicy() > Qt::StrongFocus) {
0338                 m_widget->setFocusPolicy(Qt::StrongFocus);
0339             }
0340             // if we've already received a layout, apply the calculated space to the
0341             // widget immediately, but we have to have really been full constructed (with a non-null
0342             // style pointer).
0343             if (!needsLayout() && style()) {
0344                 resizeWidget(m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(),
0345                              m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom());
0346             } else {
0347                 setPos(xPos(), -500000);
0348             }
0349         }
0350         m_view->setWidgetVisible(this, false);
0351         if (m_widget) {
0352             m_widget->move(0, -500000);
0353             m_widget->hide();
0354         }
0355     }
0356 }
0357 
0358 void RenderWidget::layout()
0359 {
0360     KHTMLAssert(needsLayout());
0361     KHTMLAssert(minMaxKnown());
0362     if (m_widget) {
0363         resizeWidget(m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(),
0364                      m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom());
0365         if (!isRedirectedWidget() && (!isFrame() || document()->part()->parentPart()) && !m_needsMask) {
0366             m_needsMask = true;
0367             RenderLayer *rl = enclosingStackingContext();
0368             RenderLayer *el = enclosingLayer();
0369             while (rl && el && el != rl) {
0370                 if (el->renderer()->style()->position() != PSTATIC) {
0371                     m_needsMask = false;
0372                     break;
0373                 }
0374                 el = el->parent();
0375             }
0376             if (m_needsMask) {
0377                 if (rl) {
0378                     rl->setHasOverlaidWidgets();
0379                 }
0380                 canvas()->setNeedsWidgetMasks();
0381             }
0382         }
0383     }
0384 
0385     setNeedsLayout(false);
0386 }
0387 
0388 void RenderWidget::updateFromElement()
0389 {
0390     if (m_widget && !qobject_cast<KHTMLView *>(m_widget)) {
0391         // Color:
0392         QColor color = style()->color();
0393         if (forceTransparentText()) {
0394             color = Qt::transparent;
0395         }
0396         QColor backgroundColor = style()->backgroundColor();
0397 
0398         if (!backgroundColor.isValid() && !style()->htmlHacks()) {
0399             backgroundColor = Qt::transparent;
0400         }
0401 
0402         bool hasBackgroundImage = style()->hasBackgroundImage();
0403         // check if we have to paint our background and let it show through the widget
0404         bool trans = (isRedirectedWidget() && !qobject_cast<KUrlRequester *>(m_widget) &&
0405                       (hasBackgroundImage || (style()->hasBackground() && shouldPaintCSSBorders())));
0406 
0407         QPalette pal(QApplication::palette(m_widget));
0408         // We need a non-transparent version for widgets with popups (e.g. kcombobox). The popups must not let
0409         // the background show through.
0410         QPalette non_trans_pal = pal;
0411 
0412         if (color.isValid() || backgroundColor.isValid() || trans) {
0413             int contrast_ = KColorScheme::contrast();
0414             int highlightVal = 100 + (2 * contrast_ + 4) * 16 / 10;
0415             int lowlightVal = 100 + (2 * contrast_ + 4) * 10;
0416             bool shouldChangeBgPal = true;
0417 
0418             if (!backgroundColor.isValid()) {
0419                 backgroundColor = pal.color(widget()->backgroundRole());
0420             } else
0421                 shouldChangeBgPal = !((backgroundColor == colorForCSSValue(CSS_VAL_WINDOW)) ||
0422                                       (backgroundColor == colorForCSSValue(CSS_VAL_BUTTONFACE)));
0423             if (shouldChangeBgPal || trans) {
0424                 pal.setColor(widget()->backgroundRole(), trans ? QColor(0, 0, 0, 0) : backgroundColor);
0425                 for (int i = 0; i < QPalette::NColorGroups; ++i) {
0426                     if (shouldChangeBgPal) {
0427                         pal.setColor((QPalette::ColorGroup)i, QPalette::Window, backgroundColor);
0428                         pal.setColor((QPalette::ColorGroup)i, QPalette::Light, backgroundColor.lighter(highlightVal));
0429                         pal.setColor((QPalette::ColorGroup)i, QPalette::Dark, backgroundColor.darker(lowlightVal));
0430                         pal.setColor((QPalette::ColorGroup)i, QPalette::Mid, backgroundColor.darker(120));
0431                         pal.setColor((QPalette::ColorGroup)i, QPalette::Midlight, backgroundColor.lighter(110));
0432                     }
0433                     pal.setColor((QPalette::ColorGroup)i, QPalette::Button, trans ? QColor(0, 0, 0, 0) : backgroundColor);
0434                     pal.setColor((QPalette::ColorGroup)i, QPalette::Base, trans ? QColor(0, 0, 0, 0) : backgroundColor);
0435                 }
0436             }
0437 
0438             if (color.isValid()) {
0439                 struct ColorSet {
0440                     QPalette::ColorGroup cg;
0441                     QPalette::ColorRole cr;
0442                 };
0443                 const struct ColorSet toSet [] = {
0444                     { QPalette::Active, QPalette::WindowText },
0445                     { QPalette::Active, QPalette::ButtonText },
0446                     { QPalette::Active, QPalette::Text },
0447                     { QPalette::Inactive, QPalette::WindowText },
0448                     { QPalette::Inactive, QPalette::ButtonText },
0449                     { QPalette::Inactive, QPalette::Text },
0450                     { QPalette::NColorGroups, QPalette::NColorRoles },
0451                 };
0452                 const ColorSet *set = toSet;
0453                 while (set->cg != QPalette::NColorGroups) {
0454                     pal.setColor(set->cg, set->cr, color);
0455                     non_trans_pal.setColor(set->cg, set->cr, color);
0456                     ++set;
0457                 }
0458 
0459                 QColor disfg = color;
0460                 int h, s, v;
0461                 disfg.getHsv(&h, &s, &v);
0462                 if (v > 128)
0463                     // dark bg, light fg - need a darker disabled fg
0464                 {
0465                     disfg = disfg.darker(lowlightVal);
0466                 } else if (v > 64)
0467                     // light bg, dark fg - need a lighter disabled fg - but only if !black
0468                 {
0469                     disfg = disfg.lighter(highlightVal);
0470                 } else
0471                     // for really dark fg - use darkgray disabled fg,
0472                     // as ::light is pretty useless in this range
0473                 {
0474                     disfg = Qt::darkGray;
0475                 }
0476                 pal.setColor(QPalette::Disabled, QPalette::WindowText, disfg);
0477                 pal.setColor(QPalette::Disabled, QPalette::Text, disfg);
0478                 pal.setColor(QPalette::Disabled, QPalette::ButtonText, disfg);
0479                 non_trans_pal.setColor(QPalette::Disabled, QPalette::WindowText, disfg);
0480                 non_trans_pal.setColor(QPalette::Disabled, QPalette::Text, disfg);
0481                 non_trans_pal.setColor(QPalette::Disabled, QPalette::ButtonText, disfg);
0482             }
0483         }
0484 
0485         if ((qobject_cast<QCheckBox *>(m_widget) || qobject_cast<QRadioButton *>(m_widget)) &&
0486                 (backgroundColor == Qt::transparent && !hasBackgroundImage)) {
0487             m_widget->setPalette(non_trans_pal);
0488         } else {
0489             m_widget->setPalette(pal);
0490         }
0491 
0492         // Combobox's popup colors
0493         if (qobject_cast<QComboBox *>(m_widget)) {
0494             // Background
0495             if (hasBackgroundImage) {
0496                 non_trans_pal = QApplication::palette();
0497             } else if (backgroundColor.isValid() && backgroundColor != Qt::transparent) {
0498                 non_trans_pal.setColor(QPalette::Base, backgroundColor);
0499             }
0500             // mmh great, there's no accessor for the popup...
0501             QList<QWidget *>l = m_widget->findChildren<QWidget *>();
0502             foreach (QWidget *w, l) {
0503                 if (QAbstractScrollArea *lView = qobject_cast<QAbstractScrollArea *>(w)) {
0504                     // we have the listview, climb up to reach its container.
0505                     assert(w->parentWidget() != m_widget);
0506                     if (w->parentWidget()) {
0507                         w->parentWidget()->setPalette(non_trans_pal);
0508                         // Set system color for vertical scrollbar
0509                         lView->verticalScrollBar()->setPalette(QApplication::palette());
0510                     }
0511                 }
0512             }
0513         } else if (QAbstractScrollArea *scrollView = qobject_cast<QAbstractScrollArea *>(m_widget)) {
0514             // Border
0515             if (QFrame *frame = qobject_cast<QFrame *>(m_widget)) {
0516                 if (shouldDisableNativeBorders()) {
0517                     if (frame->frameShape() != QFrame::NoFrame) {
0518                         m_nativeFrameShape = frame->frameShape();
0519                         frame->setFrameShape(QFrame::NoFrame);
0520                     }
0521                 } else if (m_nativeFrameShape != QFrame::NoFrame) {
0522                     frame->setFrameShape(m_nativeFrameShape);
0523                 }
0524             }
0525             // Scrollbars color (ie css extension)
0526             scrollView->horizontalScrollBar()->setPalette(style()->palette());
0527             scrollView->verticalScrollBar()->setPalette(style()->palette());
0528         } else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_widget)) {
0529             lineEdit->setFrame(!shouldDisableNativeBorders());
0530         }
0531     }
0532 
0533     RenderReplaced::updateFromElement();
0534 }
0535 
0536 void RenderWidget::paintBoxDecorations(PaintInfo &paintInfo, int _tx, int _ty)
0537 {
0538     QRect r = QRect(_tx, _ty, width(), height());
0539     QRect cr = r.intersected(paintInfo.r);
0540 
0541     if (qobject_cast<QAbstractScrollArea *>(m_widget) || (isRedirectedWidget() &&
0542             (style()->hasBackgroundImage() || (style()->hasBackground() && shouldPaintCSSBorders())))) {
0543         paintAllBackgrounds(paintInfo.p, style()->backgroundColor(), style()->backgroundLayers(),
0544                             cr, r.x(), r.y(), r.width(), r.height());
0545     }
0546 
0547     if (shouldPaintCSSBorders() && style()->hasBorder()) {
0548         paintBorder(paintInfo.p, _tx, _ty, width(), height(), style());
0549     }
0550 }
0551 
0552 void RenderWidget::slotWidgetDestructed()
0553 {
0554     if (m_view) {
0555         m_view->setWidgetVisible(this, false);
0556     }
0557     m_widget = nullptr;
0558 }
0559 
0560 void RenderWidget::setStyle(RenderStyle *_style)
0561 {
0562     RenderReplaced::setStyle(_style);
0563     if (m_widget) {
0564         m_widget->setFont(style()->font());
0565         if (style()->visibility() != VISIBLE) {
0566             if (m_view) {
0567                 m_view->setWidgetVisible(this, false);
0568             }
0569             m_widget->hide();
0570         }
0571     }
0572 }
0573 
0574 void RenderWidget::paint(PaintInfo &paintInfo, int _tx, int _ty)
0575 {
0576 
0577     // not visible or not even once layouted
0578     if (style()->visibility() != VISIBLE || m_y <= -500000) {
0579         return;
0580     }
0581 
0582     _tx += m_x;
0583     _ty += m_y;
0584 
0585     int os = maximalOutlineSize(paintInfo.phase);
0586     if ((_ty - os > paintInfo.r.bottom()) || (_ty + m_height + os <= paintInfo.r.top()) ||
0587             (_tx + m_width + os <= paintInfo.r.left()) || (_tx - os > paintInfo.r.right())) {
0588         return;
0589     }
0590 
0591     if ((paintInfo.phase == PaintActionChildBackground || paintInfo.phase == PaintActionChildBackgrounds) &&
0592             shouldPaintBackgroundOrBorder() && !qobject_cast<KUrlRequester *>(m_widget)) {
0593         paintBoxDecorations(paintInfo, _tx, _ty);
0594     }
0595 
0596     if (paintInfo.phase == PaintActionOutline && style()->outlineWidth()) {
0597         paintOutline(paintInfo.p, _tx, _ty, width(), height(), style());
0598     }
0599 
0600     if (!m_widget || !m_view || paintInfo.phase != PaintActionForeground) {
0601         return;
0602     }
0603 
0604     int xPos = _tx + borderLeft() + paddingLeft();
0605     int yPos = _ty + borderTop() + paddingTop();
0606 
0607     bool khtmlw = isRedirectedWidget();
0608     int childw = m_widget->width();
0609     int childh = m_widget->height();
0610     if ((childw == 2000 || childh == 3072) && m_widget->inherits("KHTMLView")) {
0611         KHTMLView *vw = static_cast<KHTMLView *>(m_widget);
0612         int cy = m_view->contentsY();
0613         int ch = m_view->visibleHeight();
0614 
0615         int childx = m_widget->pos().x();
0616         int childy = m_widget->pos().y();
0617 
0618         int xNew = xPos;
0619         int yNew = childy;
0620 
0621         //         qDebug("cy=%d, ch=%d, childy=%d, childh=%d", cy, ch, childy, childh );
0622         if (childh == 3072) {
0623             if (cy + ch > childy + childh) {
0624                 yNew = cy + (ch - childh) / 2;
0625             } else if (cy < childy) {
0626                 yNew = cy + (ch - childh) / 2;
0627             }
0628 //             qDebug("calculated yNew=%d", yNew);
0629         }
0630         yNew = qMin(yNew, yPos + m_height - childh);
0631         yNew = qMax(yNew, yPos);
0632         if (yNew != childy || xNew != childx) {
0633             if (vw->contentsHeight() < yNew - yPos + childh) {
0634                 vw->resizeContents(vw->contentsWidth(), yNew - yPos + childh);
0635             }
0636             vw->setContentsPos(xNew - xPos, yNew - yPos);
0637         }
0638         xPos = xNew;
0639         yPos = yNew;
0640     }
0641     m_view->setWidgetVisible(this, true);
0642     if (!khtmlw) {
0643         m_view->addChild(m_widget, xPos, yPos);
0644     } else {
0645         m_view->addChild(m_widget, xPos, -500000 + yPos);
0646     }
0647     m_widget->show();
0648     if (khtmlw) {
0649         if (KHTMLView *v = qobject_cast<KHTMLView *>(m_widget)) {
0650             // our buffers are dedicated to scrollbars.
0651             if (v->verticalScrollBar()->isVisible() && (!m_buffer[0] || v->verticalScrollBar()->size() != m_buffer[0]->size())) {
0652                 delete m_buffer[0];
0653                 m_buffer[0] = new QPixmap(v->verticalScrollBar()->size());
0654             }
0655             if (v->horizontalScrollBar()->isVisible() && (!m_buffer[1] || v->horizontalScrollBar()->size() != m_buffer[1]->size())) {
0656                 delete m_buffer[1];
0657                 m_buffer[1] = new QPixmap(v->horizontalScrollBar()->size());
0658             }
0659         } else if (!m_buffer[0] || (m_widget->size() != m_buffer[0]->size())) {
0660             assert(!m_buffer[1]);
0661             delete m_buffer[0];
0662             m_buffer[0] = new QPixmap(m_widget->size());
0663         }
0664         paintWidget(paintInfo, m_widget, xPos, yPos, m_buffer);
0665     }
0666 }
0667 
0668 static void setInPaintEventFlag(QWidget *w, bool b = true, bool recurse = true)
0669 {
0670     w->setAttribute(Qt::WA_WState_InPaintEvent, b);
0671 
0672     if (!recurse) {
0673         return;
0674     }
0675     if (qobject_cast<KHTMLView *>(w)) {
0676         setInPaintEventFlag(static_cast<KHTMLView *>(w)->widget(), b, false);
0677         setInPaintEventFlag(static_cast<KHTMLView *>(w)->horizontalScrollBar(), b, false);
0678         setInPaintEventFlag(static_cast<KHTMLView *>(w)->verticalScrollBar(), b, false);
0679         return;
0680     }
0681 
0682     foreach (QObject *o, w->children()) {
0683         QWidget *const cw = static_cast<QWidget *>(o);
0684         if (o->isWidgetType() && ! cw->isWindow()
0685                 && !(cw->windowModality() & Qt::ApplicationModal)) {
0686             setInPaintEventFlag(cw, b);
0687         }
0688     }
0689 }
0690 
0691 static void copyWidget(const QRect &r, QPainter *p, QWidget *widget, int tx, int ty, bool buffered = false, QPixmap *buffer = nullptr)
0692 {
0693     if (r.isNull() || r.isEmpty()) {
0694         return;
0695     }
0696 
0697     QPoint thePoint(tx, ty);
0698     QTransform t = p->worldTransform();
0699 
0700     if (!buffered && t.isTranslating()) {
0701         thePoint.setX(thePoint.x() + static_cast<int>(t.dx()));
0702         thePoint.setY(thePoint.y() + static_cast<int>(t.dy()));
0703     }
0704     QPixmap *pm = nullptr;
0705     QPaintDevice *d = p->device();
0706 #ifdef IN_PLACE_WIDGET_PAINTING
0707     QPaintDevice *x = d;
0708     bool vte = p->viewTransformEnabled();
0709     bool wme = p->worldMatrixEnabled();
0710     QRect w = p->window();
0711     QRect v = p->viewport();
0712     QRegion rg = p->clipRegion();
0713     qreal op = p->opacity();
0714     QPen pen = p->pen();
0715     QBrush brush = p->brush();
0716     QPainter::RenderHints rh = p->renderHints();
0717 #endif
0718     if (buffered) {
0719         if (!widget->size().isValid()) {
0720             return;
0721         }
0722         // TT says Qt 4's widget painting hits an NVidia RenderAccel bug/shortcoming
0723         // resulting in pixmap buffers being unsuitable for reuse by more than one widget.
0724         //
0725         // Until a turnaround exist in Qt, we can't reliably use shared buffers.
0726         // ###  pm = PaintBuffer::grab(widget->size());
0727         assert(buffer);
0728         pm = buffer;
0729         if (!pm->hasAlphaChannel()) {
0730             pm->fill(Qt::transparent);
0731         } else {
0732             QPainter pp(pm);
0733             pp.setCompositionMode(QPainter::CompositionMode_Source);
0734             pp.fillRect(r, Qt::transparent);
0735         }
0736         d = pm;
0737     } else {
0738         p->end();
0739     }
0740 
0741     setInPaintEventFlag(widget, false);
0742 
0743     widget->render(d, (buffered ? QPoint(0, 0) : thePoint) + r.topLeft(), r);
0744 
0745     setInPaintEventFlag(widget);
0746 
0747     if (!buffered) {
0748 #ifdef IN_PLACE_WIDGET_PAINTING
0749         p->begin(x);
0750         p->setWorldTransform(t);
0751         p->setWindow(w);
0752         p->setViewport(v);
0753         p->setViewTransformEnabled(vte);
0754         p->setWorldMatrixEnabled(wme);
0755         p->setRenderHints(rh);
0756         if (!rg.isEmpty()) {
0757             p->setClipRegion(rg);
0758         }
0759         if (op < 1.0f) {
0760             p->setOpacity(op);
0761         }
0762         p->setPen(pen);
0763         p->setBrush(brush);
0764 #else
0765         assert(false);
0766 #endif
0767     } else {
0768         // transfer results
0769         QPoint off(r.x(), r.y());
0770         p->drawPixmap(thePoint + off, static_cast<QPixmap &>(*d), r);
0771         // ### PaintBuffer::release(pm);
0772     }
0773 }
0774 
0775 void RenderWidget::paintWidget(PaintInfo &pI, QWidget *widget, int tx, int ty, QPixmap *buffer[])
0776 {
0777     QPainter *const p = pI.p;
0778     allowWidgetPaintEvents = true;
0779 
0780     bool buffered =
0781 #ifdef IN_PLACE_WIDGET_PAINTING
0782         p->combinedMatrix().m22() != 1.0 || (p->device()->devType() == QInternal::Printer);
0783 #else
0784         true;
0785 #endif
0786     QRect rr = pI.r;
0787     rr.translate(-tx, -ty);
0788     const QRect r = widget->rect().intersected(rr);
0789     if (KHTMLView *v = qobject_cast<KHTMLView *>(widget)) {
0790         QPoint thePoint(tx, ty);
0791         if (v->verticalScrollBar()->isVisible()) {
0792             QRect vbr = v->verticalScrollBar()->rect();
0793             QPoint of = v->verticalScrollBar()->mapTo(v, QPoint(vbr.x(), vbr.y()));
0794             vbr.translate(of);
0795             vbr &= r;
0796             vbr.translate(-of);
0797             if (vbr.isValid() && !vbr.isEmpty()) {
0798                 copyWidget(vbr, p, v->verticalScrollBar(), tx + of.x(), ty + of.y(), buffered, buffer[0]);
0799             }
0800         }
0801         if (v->horizontalScrollBar()->isVisible()) {
0802             QRect hbr = v->horizontalScrollBar()->rect();
0803             QPoint of = v->horizontalScrollBar()->mapTo(v, QPoint(hbr.x(), hbr.y()));
0804             hbr.translate(of);
0805             hbr &= r;
0806             hbr.translate(-of);
0807             if (hbr.isValid() && !hbr.isEmpty()) {
0808                 copyWidget(hbr, p, v->horizontalScrollBar(), tx + of.x(), ty + of.y(), buffered, buffer[1]);
0809             }
0810         }
0811         QPoint of = v->viewport()->mapTo(v, QPoint(0, 0));
0812         QRect vr = (r & v->viewport()->rect().translated(of));
0813         if (vr.isValid() && !vr.isEmpty()) {
0814             v->render(p, vr, thePoint);
0815         }
0816     } else {
0817         copyWidget(r, p, widget, tx, ty, buffered, buffer[0]);
0818     }
0819     allowWidgetPaintEvents = false;
0820 }
0821 
0822 bool RenderWidget::eventFilter(QObject * /*o*/, QEvent *e)
0823 {
0824     // no special event processing if this is a frame (in which case KHTMLView handles it all)
0825     if (qobject_cast<KHTMLView *>(m_widget) || isRedirectedWidget()) {
0826         return false;
0827     }
0828     if (!element()) {
0829         return true;
0830     }
0831 
0832     static bool directToWidget = false;
0833     if (directToWidget) {
0834         //We're trying to get the event to the widget
0835         //promptly. So get out of here..
0836         return false;
0837     }
0838 
0839     ref();
0840     element()->ref();
0841 
0842     bool filtered = false;
0843 
0844     //qCDebug(KHTML_LOG) << "RenderWidget::eventFilter type=" << e->type();
0845     switch (e->type()) {
0846     case QEvent::FocusOut:
0847         // First, forward it to the widget, so that Qt gets a precise
0848         // state of the focus before pesky JS can try changing it..
0849         directToWidget = true;
0850         QApplication::sendEvent(m_widget, e);
0851         directToWidget = false;
0852         filtered       = true; //We already delivered it!
0853 
0854         // Don't count popup as a valid reason for losing the focus
0855         // (example: opening the options of a select combobox shouldn't emit onblur)
0856         if (static_cast<QFocusEvent *>(e)->reason() != Qt::PopupFocusReason) {
0857             handleFocusOut();
0858         }
0859         break;
0860     case QEvent::FocusIn:
0861         //As above, forward to the widget first...
0862         directToWidget = true;
0863         QApplication::sendEvent(m_widget, e);
0864         directToWidget = false;
0865         filtered       = true; //We already delivered it!
0866 
0867         //qCDebug(KHTML_LOG) << "RenderWidget::eventFilter captures FocusIn";
0868         document()->setFocusNode(element());
0869 //         if ( isEditable() ) {
0870 //             KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>( element()->view->part()->browserExtension() );
0871 //             if ( ext )  ext->editableWidgetFocused( m_widget );
0872 //         }
0873         break;
0874     case QEvent::Wheel: {
0875         if (widget()->parentWidget() == view()->widget()) {
0876             bool vertical = (static_cast<QWheelEvent *>(e)->orientation() == Qt::Vertical);
0877             // don't allow the widget to react to wheel event if
0878             // the view is being scrolled by mouse wheel
0879             // This does not apply if the webpage has no valid scroll range in the given wheel event orientation.
0880             if (((vertical && (view()->contentsHeight() > view()->visibleHeight()))  ||
0881                     (!vertical && (view()->contentsWidth() > view()->visibleWidth()))) &&
0882                     view()->isScrollingFromMouseWheel())  {
0883                 static_cast<QWheelEvent *>(e)->ignore();
0884                 QApplication::sendEvent(view(), e);
0885                 filtered = true;
0886             }
0887         }
0888         break;
0889     }
0890     case QEvent::KeyPress:
0891     case QEvent::KeyRelease:
0892         // TODO this seems wrong - Qt events are not correctly translated to DOM ones,
0893         // like in KHTMLView::dispatchKeyEvent()
0894         if (element()->dispatchKeyEvent(static_cast<QKeyEvent *>(e), false)) {
0895             filtered = true;
0896         }
0897         break;
0898 
0899     default:
0900         break;
0901     };
0902 
0903     element()->deref();
0904 
0905     // stop processing if the widget gets deleted, but continue in all other cases
0906     if (hasOneRef()) {
0907         filtered = true;
0908     }
0909     deref();
0910 
0911     return filtered;
0912 }
0913 
0914 void RenderWidget::EventPropagator::sendEvent(QEvent *e)
0915 {
0916     // ### why don't we just call event()? That would be the normal route.
0917     switch (e->type()) {
0918     case QEvent::Wheel:
0919         wheelEvent(static_cast<QWheelEvent *>(e));
0920         break;
0921     case QEvent::MouseButtonPress:
0922         mousePressEvent(static_cast<QMouseEvent *>(e));
0923         break;
0924     case QEvent::MouseButtonRelease:
0925         mouseReleaseEvent(static_cast<QMouseEvent *>(e));
0926         break;
0927     case QEvent::MouseButtonDblClick:
0928         mouseDoubleClickEvent(static_cast<QMouseEvent *>(e));
0929         break;
0930     case QEvent::MouseMove:
0931         mouseMoveEvent(static_cast<QMouseEvent *>(e));
0932         break;
0933     case QEvent::KeyPress:
0934         keyPressEvent(static_cast<QKeyEvent *>(e));
0935         break;
0936     case QEvent::KeyRelease:
0937         if (qobject_cast<QLineEdit *>(this)) {
0938             event(e);
0939         } else {
0940             keyReleaseEvent(static_cast<QKeyEvent *>(e));
0941         }
0942         break;
0943     case QEvent::FocusIn:
0944         focusInEvent(static_cast<QFocusEvent *>(e));
0945         break;
0946     case QEvent::FocusOut:
0947         focusOutEvent(static_cast<QFocusEvent *>(e));
0948         break;
0949     case QEvent::ContextMenu:
0950         contextMenuEvent(static_cast<QContextMenuEvent *>(e));
0951         break;
0952     default:
0953         break;
0954     }
0955 }
0956 
0957 // send event to target and let it bubble up until it is accepted or
0958 // once it would go through a limiting widget level
0959 static bool bubblingSend(QWidget *target, QEvent *e, QWidget *stoppingParent)
0960 {
0961     for (;;) {
0962         static_cast<RenderWidget::EventPropagator *>(target)->sendEvent(e);
0963         if (e->isAccepted()) {
0964             return true;
0965         }
0966         if (target == stoppingParent) {
0967             return false;
0968         }
0969         // ### might want to shift Q*Event::pos() as we go up
0970         target = target->parentWidget();
0971         assert(target != nullptr);
0972     }
0973 }
0974 
0975 bool RenderWidget::handleEvent(const DOM::EventImpl &ev)
0976 {
0977     bool ret = false;
0978 
0979     switch (ev.id()) {
0980     case EventImpl::DOMFOCUSIN_EVENT:
0981     case EventImpl::DOMFOCUSOUT_EVENT: {
0982         QFocusEvent e(ev.id() == EventImpl::DOMFOCUSIN_EVENT ? QEvent::FocusIn : QEvent::FocusOut);
0983         // E.g. a KLineEdit child widget might be defined to receive
0984         // focus instead
0985         QWidget *fw = m_widget->focusProxy() ? m_widget->focusProxy() : m_widget;
0986         static_cast<EventPropagator *>(fw)->sendEvent(&e);
0987         ret = e.isAccepted();
0988         break;
0989     }
0990     case EventImpl::KHTML_MOUSEWHEEL_EVENT:
0991     case EventImpl::MOUSEDOWN_EVENT:
0992     case EventImpl::MOUSEUP_EVENT:
0993     case EventImpl::MOUSEMOVE_EVENT: {
0994         if (!ev.isMouseEvent()) {
0995             break;
0996         }
0997 
0998         const MouseEventImpl &me = static_cast<const MouseEventImpl &>(ev);
0999         QMouseEvent *const qme = me.qEvent();
1000         QMouseEvent::Type type;
1001         Qt::MouseButton button = Qt::NoButton;
1002         Qt::MouseButtons buttons = Qt::NoButton;
1003         Qt::KeyboardModifiers state = Qt::NoModifier;
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:
1030                 type = QMouseEvent::MouseButtonPress;
1031                 break;
1032             case EventImpl::MOUSEUP_EVENT:
1033                 type = QMouseEvent::MouseButtonRelease;
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
1116             QMouseEvent evt(QEvent::MouseMove, p, Qt::NoButton,
1117                             QApplication::mouseButtons(), QApplication::keyboardModifiers());
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) {
1171             QContextMenuEvent cme(QContextMenuEvent::Mouse, p);
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 
1351 #include "moc_render_replaced.cpp"